逆波兰表达式——中缀表达式转后缀表达式

Posted lanhaicode

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了逆波兰表达式——中缀表达式转后缀表达式相关的知识,希望对你有一定的参考价值。

逆波兰表达式

先说一下中缀表达式,平时我们使用的运算表达式就是中缀表达式,例如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 }
View Code

 

后缀表达式的计算

完成了中缀表达式转后缀表达式,接下来就是后缀表达式的计算了,后缀表达式的计算比中缀转后缀要稍微简单一点,只需要对我们转换好的后缀表达式从左往右依次扫描,并依次入栈就行了,

意思是只需要用一个数组(double num[100])就OK了

需要考虑的情况如下

1、如果是数字,那么直接入栈到num中

2、如果是运算符,将栈顶的两个数字出栈(因为我们考虑的运算符加、减、乘、除都是双目运算符,只需要两个操作数),出栈后对两个数字进行相应的运算,并将运算结果入栈

3、直到遇到‘\\0‘

下面用几张图,来直观了解下这个过程,以上面转换好的后缀表达式"123+*"为例(这里用ss来存储后缀表达式,num来存储计算结果,注意不要与上面图中num搞混淆了)

技术图片

技术图片

 

技术图片

 

技术图片

(注意:这里将计算结果5入栈后,栈顶从之前的[3]变成[2])

技术图片

技术图片

到这里后缀表达式的计算就结束了,下面附上实现代码

技术图片
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 
  4 #define MAX 100
  5 
  6 void JudgeFopen_s(errno_t err);
  7 void ReadFile(FILE *fp, char *ss);
  8 double TransformCtoD(char ch);
  9 
 10 int main()
 11 {
 12     FILE *fp;
 13     errno_t err;
 14 
 15     char ss[MAX];    /* 存储逆波兰表达式 */
 16     int i = 0;
 17     int j = 0;
 18     double num[MAX];    /**/
 19     
 20     err = fopen_s(&fp, "E:\\\\ww.txt", "r");
 21 
 22     JudgeFopen_s(err);
 23     ReadFile(fp, ss);
 24 
 25     while (ss[i] != \\0)
 26     {
 27         if (ss[i] >= 0 && ss[i] <= 9)    /* 如果是数字 */
 28         {
 29             /* 因为num是char类型的,需要转换为double类型方便计算 */
 30             num[j] = TransformCtoD(ss[i]);    /* 将数字存储到栈中 */
 31             j++;
 32             i++;
 33         }
 34         else if (ss[i] == + || ss[i] == - || ss[i] == * || ss[i] == /)
 35         {
 36             switch (ss[i])
 37             {
 38             case +:
 39                 {
 40                     num[j-2] = num[j-1] + num[j-2];
 41                     j = j-1;
 42                     i++;    /* 表达式中的下一个元素 */
 43                     break;
 44                 }
 45             case -:
 46                 {
 47                     num[j-2] = num[j-2] - num[j-1];
 48                     j = j-1;    
 49                     i++;
 50                     break;
 51                 }
 52             case *:
 53                 {
 54                     num[j-2] = num[j-2] * num[j-1];
 55                     j = j-1;
 56                     i++;
 57                     break;
 58                 }
 59             case /:
 60                 {
 61                     num[j-2] = num[j-2] / num[j-1];
 62                     j = j-1;
 63                     i++;
 64                     break;
 65                 }
 66             default:exit(0);
 67             }
 68         }
 69         else if (ss[i] == \\n)
 70         {
 71             break;
 72         }
 73     }
 74 
 75     printf("%lf", num[0]);
 76     return 0;
 77 }
 78 
 79 void JudgeFopen_s(errno_t err)
 80 {
 81     if (err != 0)
 82     {
 83         printf("文件打开失败\\n");
 84         system("pause");
 85         exit(0);
 86     }
 87 }
 88 void ReadFile(FILE *fp, char *ss)
 89 {
 90     int i = 0;
 91 
 92     while (!feof(fp))
 93     {
 94         fscanf_s(fp, "%c", &ss[i]);
 95         i++;
 96     }
 97     ss[i-1] = \\0;
 98 }
 99 double TransformCtoD(char ch)
100 {
101     return (double)(ch - 0);
102 }
View Code

以上是关于逆波兰表达式——中缀表达式转后缀表达式的主要内容,如果未能解决你的问题,请参考以下文章

算法逆波兰式(后缀表达式)的计算 & 中缀表达式转后缀表达式(逆波兰式)

中缀表达式转后缀表达式(逆波兰表达式)

算法中缀表达式转成后缀表达式(逆波兰表达式)再计算得出结果

算法中缀表达式转成后缀表达式(逆波兰表达式)再计算得出结果

shunting-yard 调度场算法中缀表达式转逆波兰表达式

逆波兰表达式