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

逆波兰表达式

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

后缀表达式的计算

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

意思是只需要用一个数组(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 }

原文地址:https://www.cnblogs.com/lanhaicode/p/10776166.html

时间: 2024-12-12 09:30:19

逆波兰表达式——中缀表达式转后缀表达式的相关文章

运用栈把算术表达式+,-,*,/,%(中缀表达式)转换成后缀表达式并且计算出值

原理: 1.首先判断是数值还是符号,如果是数值放进字符数组以#表示结束, 2.如果是符号,放进栈, 3.每个符号之间要比较优先级,如果栈顶符号优先级低,符号进栈,如果相等(即“(” “)”)出栈,栈顶符号优先级高,栈顶元素出栈进入字符数组,得到后缀表达式 4.计算后缀表达式,判断是数字还是符号.直到遇到符号,将前面的数字计算后放进栈,一直重复,知道“\0” 代码(局限用整数,因为有模运算,若要任何类型的代码,我的blog有) 1 #include <stdio.h> 2 #include &l

逆波兰表达式的实现(也叫后缀表达式)

本文主要偏重实现如何将字符串表达式转换为逆波兰表达式. 关于其讲解参考我转载的一篇博文:http://www.cnblogs.com/vpoet/p/4659546.html 先说说优先级: ()    +-     */%(从左到右递增) 下面先简单再梳理一下: 1.建立两个栈,一个为N(数据栈),一个为OP(运算符栈) 2.将字符串从左向右遍历,把数据压入数据栈,把运算符压入运算符的栈   关于运算符压栈的规则:⑴ 如果OP为空直接将运算符压入栈 ⑵ 如果不为空,则比较待入栈元素和栈顶元素的

中缀表达式与前、后缀表达式转化简单的技巧[转]

35,15,+,80,70,-,*,20,/ //后缀表达方式 (((35+15)*(80-70))/20)=25 //中缀表达方式 /,*,+,35,15,-,80,70, 20 //前缀表达方式 人的思维方式很容易固定~~!正如习惯拉10进制.就对2,3,4,8,16等进制不知所措一样~~! 人们习惯的运算方式是中缀表达式.而碰到前缀,后缀方式..迷茫其实仅仅是一种表达式子的方式而已(不被你习惯的方式) 我这里教你一种也许你老师都没跟你讲的简单转换方式 一个中缀式到其他式子的转换方法 这里我

中缀表达式转前缀和后缀表达式

中缀转前缀 #ifndef POSTFIX_TO_NIFIXEXPRESS_H #define POSTFIX_TO_NIFIXEXPRESS_H #include<iostream> #include<string> #include<stack> /************************************************************************/ /* 中缀表达式转前缀表达式 建立一个栈来保存运算符,和一个字符容器存字

中缀表达式检测并转换后缀表达式,计算后缀表达式的结果

实现代码如下 #include <iostream> #include <stack> #include <ctype.h> using namespace std; //这里的数字只能是一位 //扫描表达式是否合法,合法返回0,否则返回非0 int Scanner(const char *str) { stack<char*> s; if(str==NULL) { return -1; } char *p=(char*)str; while(*p!='\0

中缀表达式转换为前、后缀表达式转化简单的技巧[转]

原文来源 https://www.cnblogs.com/Hslim/p/5008460.html 这里我给出一个中缀表达式 1 a+b*c-(d+e)    //中缀表达 第一步:按照运算符的优先级对所有的运算单位加括号 式子变成:((a+(b*c))-(d+e))第二步:转换前缀与后缀表达式        前缀:把运算符号移动到对应的括号前面                则变成:-( +(a *(bc)) +(de)) //这里移动时                把括号去掉:-+a*bc

表达式求值(后缀表达式求值)

表达式求值 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 ACM队的mdd想做一个计算器,但是,他要做的不仅仅是一计算一个A+B的计算器,他想实现随便输入一个表达式都能求出它的值的计算器,现在请你帮助他来实现这个计算器吧. 比如输入:“1+2/4=”,程序就输出1.50(结果保留两位小数) 输入 第一行输入一个整数n,共有n组测试数据(n<10). 每组测试数据只有一行,是一个长度不超过1000的字符串,表示这个运算式,每个运算式都是以“=”结束.这个表达式里只包

数据结构——逆波兰式

很久没有关注算法和数据结构,大部分知识都已经忘记了:是时间好好回炉一下了,说实话干读数据机构这本书还是挺枯燥而且这本书原理性比较多,有一定的难度.这不刚看到逆波兰式废了好大劲才搞懂,老了... 逆波兰式 逆波兰式(Reverse Polish notation,RPN,或逆波兰记法),也叫后缀表达式(将运算符写在操作数之后) 一个表达式E的后缀形式可以如下定义: (1)如果E是一个变量或常量,则E的后缀式是E本身. (2)如果E是E1 op E2形式的表达式,这里op是如何二元操作符,则E的后缀

栈的应用-逆波兰式

---恢复内容开始--- 普通的计算方式,也叫中缀表达式计算机识别及正确运用需要耗费大量的资源 23+45*2-(8+2) 计算机想要正确计算出此时的结果需要十分复杂,更何况情况十分多变. 逆波兰式:又叫做后缀表达式,它能去除中缀表达式的括号.十分符合计算机的计算思维,能极大提高效率 表达式不能用字符串进行存储,因为这将无法分辨,应用集合(ArrayList,LinkedList存储) 23 45 2 * 8 2 + - + 那么中缀表达式是如何变成后缀表达式的呢?原则如下: 1.首先把普通的表

栈实现综合计算器(中缀表达式),前缀,中缀,后缀表达式,逆波兰计算器

思路: 代码:实现多位数的运算 public class Calculator { public static void main(String[] args) { //根据前面老师思路,完成表达式的运算 String expression = "7*2*2-5+1-5+3-4"; // 15//如何处理多位数的问题? //创建两个栈,数栈,一个符号栈 ArrayStack2 numStack = new ArrayStack2(10); ArrayStack2 operStack =