先说一下中缀表达式,平时我们使用的运算表达式就是中缀表达式,例如1+3*2,中缀表达式的特点就是:二元运算符总是置于与之相关的两个运算对象之间
人读起来比较好理解,但是计算机处理起来就很麻烦,运算顺序往往因表达式的内容而定,不具规律性
后缀表达式,后缀表达式的特点就是:每一运算符都置于其运算对象之后,以上面的中缀表达式1+2*3为例子,转为后缀表达式就是123*+
下面先分析怎么把中缀表达式转换为后缀表达式,这里我们考虑六种操作符'+'、'-'、'*'、'/'、'('、')',完成中缀转后缀我们需要两个数组,都以栈的方式来操作,一个数组用来存放后缀表达式(char num[100]),
一个数组用来临时存放操作数(char opera[100])(这里说临时存放,是因为最后都要入栈到后缀表达式数组num中,这个数组就相当于一个中转站)
1、从左往右扫描中缀表达式(这里我们以1*(2+3)为例)
2、如果是数字那么将其直接入栈到数组num中
3、如果是操作数,需要进一步判断
(1)如果是左括号'('直接入栈到数组opera中
(2)如果是运算符('+'、'-'、'*'、'/'),先判断数组opera的栈顶的操作数的优先级(如果是空栈那么直接入栈到数组opera),如果是左括号那么直接入栈到数组opera中,如果栈顶是运算符,且栈顶运算符的优先级大于该运算符
那么将栈顶的运算符出栈,并入栈到数组num中,重复步骤3,如果栈顶运算符优先级小于该运算符,那么直接将该运算符入栈到opera中
(3)如果是右括号')',那么说明在opera数组中一定有一个左括号与之对应(在你没输错的情况下),那么将opera中的运算符依次出栈,并入栈到num中,直到遇到左括号'('(注意左括号不用入栈到num)
4、如果中缀表达式扫描完了,那么将opera中的操作数依次出栈,并入栈到num中就可以了,如果没有没有扫描完重复1-3步
上面就是中缀表达式转后缀表达式的步骤了,下面用图来直观的了解一下这个过程
需要注意的是:opera中操作数,越靠近栈顶,优先级越高,下面附上实现代码
1 void PexpretoSexpre(char *ss) 2 { 3 char num[100] = "0"; /* 存储后缀表达式 */ 4 char opera[100] = "0"; /* 存储运算符 */ 5 /* 6 num----j 7 opera----op 8 ss----i 9 */ 10 int i, j, op; 11 12 op = i = j = 0; 13 14 while (ss[i] != '\0') 15 { 16 if (isdigit(ss[i])) /* 如果是数字 */ 17 { 18 num[j] = ss[i]; /* 数字直接入后缀表达式栈 */ 19 j++; 20 i++; 21 } 22 else 23 { 24 switch (ss[i]) /* 如果是操作数 */ 25 { 26 case '+': 27 { 28 if (op == 0) /* 如果是空栈 */ 29 { 30 PushOperation(opera, ss, &op, &i); /* 入运算符栈 */ 31 break; 32 } 33 if (opera[op-1] == '+' || opera[op-1] == '-' || opera[op-1] == '*' || opera[op-1] == '/' || opera[op-1] == ')' || opera[op-1] == '(') 34 { 35 switch (opera[op-1]) 36 { 37 case '+': 38 { 39 PushOperation(opera, ss, &op, &i); 40 break; 41 } 42 case '-': 43 { 44 PushOperation(opera, ss, &op, &i); 45 break; 46 } 47 case '*': 48 { /* 加法优先级低于乘法 */ 49 num[j] = opera[op-1]; /* 将操作数出栈 */ 50 opera[op-1] = ss[i]; /* 将新的操作数压入栈中 */ 51 j++; 52 i++; 53 break; 54 } 55 case '/': 56 { 57 num[j] = opera[op-1]; 58 opera[op-1] = ss[i]; 59 j++; 60 i++; 61 break; 62 } 63 case '(': 64 { 65 PushOperation(opera, ss, &op, &i); 66 break; 67 } 68 } 69 } 70 break; 71 } 72 case '-': 73 { 74 if (op == 0) 75 { 76 PushOperation(opera, ss, &op, &i); 77 break; 78 } 79 if (opera[op-1] == '+' || opera[op-1] == '-' || opera[op-1] == '*' || opera[op-1] == '/' || opera[op-1] == ')' || opera[op-1] == '(') 80 { 81 switch (opera[op-1]) 82 { 83 case '+': 84 { 85 PushOperation(opera, ss, &op, &i); 86 break; 87 } 88 case '-': 89 { 90 PushOperation(opera, ss, &op, &i); 91 break; 92 } 93 case '*': 94 { 95 num[j] = opera[op-1]; 96 opera[op-1] = ss[i]; 97 j++; 98 i++; 99 break; 100 } 101 case '/': 102 { 103 num[j] = opera[op-1]; 104 opera[op-1] = ss[i]; 105 j++; 106 i++; 107 break; 108 } 109 case '(': 110 { 111 PushOperation(opera, ss, &op, &i); 112 break; 113 } 114 } 115 } 116 break; 117 } 118 case '*': 119 { 120 if (op == 0) 121 { 122 PushOperation(opera, ss, &op, &i); 123 break; 124 } 125 if (opera[op-1] == '+' || opera[op-1] == '-' || opera[op-1] == '*' || opera[op-1] == '/' || opera[op-1] == ')' || opera[op-1] == '(') 126 { 127 switch (opera[op-1]) 128 { 129 case '+': 130 { 131 PushOperation(opera, ss, &op, &i); 132 break; 133 } 134 case '-': 135 { 136 PushOperation(opera, ss, &op, &i); 137 break; 138 } 139 case '*': 140 { 141 PushOperation(opera, ss, &op, &i); 142 break; 143 } 144 case '/': 145 { 146 PushOperation(opera, ss, &op, &i); 147 break; 148 } 149 case '(': 150 { 151 PushOperation(opera, ss, &op, &i); 152 break; 153 } 154 } 155 } 156 break; 157 } 158 case '/': 159 { 160 if (op == 0) 161 { 162 PushOperation(opera, ss, &op, &i); 163 break; 164 } 165 if (opera[op-1] == '+' || opera[op-1] == '-' || opera[op-1] == '*' || opera[op-1] == '/' || opera[op-1] == ')' || opera[op-1] == '(') 166 { 167 switch (opera[op-1]) 168 { 169 case '+': 170 { 171 PushOperation(opera, ss, &op, &i); 172 break; 173 } 174 case '-': 175 { 176 PushOperation(opera, ss, &op, &i); 177 break; 178 } 179 case '*': 180 { 181 PushOperation(opera, ss, &op, &i); 182 break; 183 } 184 case '/': 185 { 186 PushOperation(opera, ss, &op, &i); 187 break; 188 } 189 case '(': 190 { 191 PushOperation(opera, ss, &op, &i); 192 break; 193 } 194 } 195 } 196 break; 197 } 198 case '(': 199 { 200 PushOperation(opera, ss, &op, &i); 201 break; 202 } 203 case ')': /* 如果遇到右括号 */ 204 { 205 while (opera[op-1] != '(') 206 { 207 num[j] = opera[op-1]; /* 将运算符栈中的元素依次入栈到后缀表达式栈中,直到遇到左括号为止 */ 208 j++; 209 op--; 210 } 211 op--; 212 i++; 213 break; 214 } 215 default: 216 { 217 printf("传入表达式不符合要求\n"); 218 exit(0); 219 } 220 221 } 222 } 223 } 224 while (op != 0) 225 { 226 num[j] = opera[op-1]; /* 将运算符栈中的元素依次入栈到后缀表达式栈中 */ 227 j++; 228 op--; 229 } 230 num[j] = '\0'; 231 i = 0; 232 while (num[i] != '\0') /* 将后缀表达式存储到传入的形参ss中 */ 233 { 234 ss[i] = num[i]; 235 i++; 236 } 237 ss[i] = '\0'; 238 } 239 240 /* Function: 入运算符栈*/ 241 void PushOperation(char *opera, char *ss, int *op, int *s) 242 { 243 opera[*op] = ss[*s]; 244 (*op)++; 245 (*s)++; 246 }