加/减/乘/除四则混合运算(C 语言)
逆波兰表达式(也称为后缀表达式) C 语言简单实现
本示例旨在展示逆波兰表达式原理,作简单的混合运算,不作容错处理也不保证结果。若混合运算字符串中有{ [ %] } 等,自行调试解决
列如计算: -20.5 + ( 100 - ( 3 + 2 ) * 8 ) / ( 8 - 5 ) - 10
后缀表达式为:-20.5 100 3 2 + 8 * - 8 5 - / + 10 -
C 语言代码如下:
1 #include显示代码2 #include 3 #include <string.h> 4 5 #define CNT 1000 6 7 struct node{ 8 float num; //数字 9 char op; //操作符 10 }; 11 12 struct node datas[CNT]; //后缀表达式 13 int data_top = -1; //栈顶索引 14 15 char ops[CNT]; //操作符 16 int op_top = -1; //栈顶索引 17 18 char nums[100]; //数字字符串 19 int num_top = -1; //栈顶索引 20 int minus_tag = 1; //负数标记 21 //数字入栈 22 void push_num(){ 23 if(num_top > -1){ 24 datas[++data_top].num = atof(nums) * minus_tag; 25 datas[data_top].op = 0; 26 num_top = -1; 27 minus_tag = 1; 28 memset(nums, 0, sizeof(nums)); 29 } 30 } 31 //中缀转后缀 32 void mtoe(const char* str){ 33 char *tmp; 34 tmp = (char*)str; 35 int last_tag = 1; //上一个字符是否是运算符,默认是,用于处理负数 36 while(*tmp != '\0'){ 37 char ch = *tmp; 38 ++tmp; 39 if(ch == ' ') continue; 40 41 if(ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '('){ 42 push_num(); 43 if( (ch == '-') && last_tag ){ 44 minus_tag = -1;//负数标记 45 last_tag = 0; 46 continue; 47 } 48 last_tag = 1; 49 while(op_top > -1){ 50 if(ch == '(') break; 51 char op = ops[op_top]; 52 if(op == '(') break; 53 if(ch == '+' || ch == '-'){ 54 datas[++data_top].op = op; 55 --op_top; 56 }else{ 57 if(op == '+' || op == '-') break; 58 else{ 59 datas[++data_top].op = op; 60 --op_top; 61 } 62 } 63 } 64 ops[++op_top] = ch; 65 }else if(ch == ')'){ 66 push_num(); 67 last_tag = 0; 68 while(ops[op_top] != '('){ 69 datas[++data_top].op = ops[op_top]; 70 --op_top; 71 } 72 --op_top; 73 }else{ 74 last_tag = 0; 75 nums[++num_top] = ch; 76 } 77 }// end of while *tmp 78 push_num();//最后的数据入栈 79 while(op_top > -1){//最后的操作符入栈 80 datas[++data_top].op = ops[op_top]; 81 --op_top; 82 } 83 84 } 85 //计算值 86 float calculating(){ 87 if(data_top < 0) return 0; 88 float stack[CNT] = {0}; 89 int top = -1; 90 int i = 0; 91 while(i <= data_top){ 92 char op = datas[i].op; 93 if(op == 0){ 94 stack[++top] = datas[i].num; 95 }else{ 96 float a = stack[top -1]; 97 float b = stack[top]; 98 --top; 99 float c = 0; 100 if(op == '+') c = a + b; 101 else if(op == '-') c = a -b; 102 else if(op == '*') c = a * b; 103 else if(op == '/') c = a / b; 104 stack[top] = c; 105 } 106 ++i; 107 } 108 if(top < 0) return 0; 109 else return stack[top]; 110 } 111 112 int main(int argc, char *argv[]){ 113 char *parms = "-20.5+(100-(3+2)*8)/(8-5) - 10"; 114 //char *parms = "10+100/2*5"; 115 data_top = -1; 116 op_top = -1; 117 num_top = -1; 118 mtoe(parms); 119 printf("\n"); 120 printf("%s = ",parms); 121 printf("%f\n",calculating()); 122 int i = 0; 123 for(i = 0; i <= data_top; i++){ 124 if(datas[i].op) printf("%c ", datas[i].op); 125 else printf("%f ",datas[i].num); 126 } 127 printf("\n\n"); 128 return 0; 129 }
执行结果:
-20.5+(100-(3+2)*8)/(8-5) - 10 = -10.500000
-20.500000 100.000000 3.000000 2.000000 + 8.000000 * - 8.000000 5.000000 - / + 10.000000 -
1 #include优化版2 #include 3 #include <string.h> 4 5 #define CNT 1000 6 7 float datas[CNT]; //数字栈 8 int data_top = -1; //栈顶索引 9 10 char nums[100]; //数字字符串 11 int num_top = -1; //栈顶索引 12 int minus_tag = 1; //负数标记 13 //数字入栈 14 void push_num(){ 15 if(num_top > -1){ 16 datas[++data_top] = atof(nums) * minus_tag; 17 num_top = -1; 18 minus_tag = 1; 19 memset(nums, 0, sizeof(nums)); 20 } 21 } 22 //操作符入栈,则计算值 23 void push_op(char op) 24 { 25 float a = datas[data_top -1]; 26 float b = datas[data_top]; 27 float c = 0; 28 if(op == '+') c = a + b; 29 else if(op == '-') c = a -b; 30 else if(op == '*') c = a * b; 31 else if(op == '/') c = a / b; 32 datas[--data_top] = c; 33 } 34 //中缀转后缀并计算值 35 void calc(const char* str){ 36 char *tmp; 37 tmp = (char*)str; 38 char ops[CNT]; 39 int op_top = -1; 40 int last_tag = 1; //上一个字符是否是运算符,默认是,用于处理负数 41 while(*tmp != '\0'){ 42 char ch = *tmp; 43 ++tmp; 44 if(ch == ' ') continue; 45 46 if(ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '('){ 47 push_num(); 48 if( (ch == '-') && last_tag ){ 49 minus_tag = -1;//负数标记 50 last_tag = 0; 51 continue; 52 } 53 last_tag = 1; 54 while(op_top > -1){ 55 if(ch == '(') break; 56 char op = ops[op_top]; 57 if(op == '(') break; 58 if(ch == '+' || ch == '-'){ 59 push_op(op); 60 --op_top; 61 }else{ 62 if(op == '+' || op == '-') break; 63 else{ 64 push_op(op); 65 --op_top; 66 } 67 } 68 } 69 ops[++op_top] = ch; 70 }else if(ch == ')'){ 71 push_num(); 72 last_tag = 0; 73 while(ops[op_top] != '('){ 74 push_op(ops[op_top]); 75 --op_top; 76 } 77 --op_top; 78 }else{ 79 last_tag = 0; 80 nums[++num_top] = ch; 81 } 82 }// end of while *tmp 83 push_num();//最后的数据入栈 84 while(op_top > -1){//最后的操作符入栈 85 push_op(ops[op_top]); 86 --op_top; 87 } 88 } 89 90 int main(int argc, char *argv[]){ 91 char *parms = "-20.5+(100-(3+2)*8)/(8-5) - 10"; 92 data_top = -1; 93 num_top = -1; 94 calc(parms); 95 printf("\n%s = ",parms); 96 printf("%f\n",datas[0]); 97 return 0; 98 }
附中缀表达式转前缀或后缀表达式原理
转化步骤:
- 按照运算符的优先级对所有的运算单位加括号
- 将运算符移动到对应括号的前面(前缀表达式)或后面(后缀表达式)
- 去掉括号,得到前缀或后缀表达式
示例:
中缀表达式:5 + ( 6 + 7 ) × 8 - 9
1)加括号
变成 ( ( 5 + ( ( 6 + 7 ) × 8 ) ) - 9 )
2)移动运算符
前缀变成了 - ( + ( 5 × ( + ( 6 7 ) 8 ) ) 9 )
后缀变成了 ( ( 5 ( ( 6 7 ) + 8 ) × ) + 9 ) -
3)去掉括号
前缀表达式: - + 5 × + 6 7 8 9
后缀表达式:5 6 7 + 8 × + 9 -