中缀表达式就是我们日常用的算术表达式。
前缀表达式是将运算符放在两个操作数之前。后缀表达式(又称逆波兰表达式)是将运算符放在两个操作数之后。例如:中缀表达式(A+(B-C/D)*E)对应的前缀表达式是(+A*-B/CDE)对应的后缀表达式为(ABCD/-E*+)
说到转化之前我们先来看一下符号的优先级问题。
运算符 | (左括号 | +加,-减 | *乘,/除,%取模 | ^幂 |
优先级 | 0 | 1 | 2 | 3 |
下面我们来弄清两个问题。
为什么我们要把中缀表达式转化为后缀表达式去计算?怎样将中缀表达式转化为后缀表达式?
第一个问题,只要提到计算器的实现,基本上都会想到使用后缀表达式来实现,后缀表达式计算机操作起来方便(例如a+b*c,计算器从左向右扫描,假设已经扫描到b那个位置了,计算器怎样知道要不要现在就计算a+b呢?是的,可以用一个判断语句来判断甚至用一个更牛的语句来判断是否立刻就要计算a+b,但是我就问你一句,你不嫌麻烦吗?后缀表达式就不一样,就很牛了,只要压入的符合后缀表达式的条件计算器就去计算吧,绝对正确。当然了,从下面给出的规则来看,后缀表达式开出的条件并不算太麻烦。何乐而不用呢?)加加减减是按照后缀表达式的顺序来的,计算机一直对栈顶元素进行操作就行了。很方便。如果你有其他的实现方法,欢迎留言。
第二个问题,怎样实现中缀表达式转化为后缀表达式?
1.初始化一个栈,栈中元素是char类型,因为是要用这个栈来储存运算符的。
2.从算数表达式输入的字符串中依次从左向右每次读取一个字符。
3.如果当前字符是操作数,则直接填写到后缀表达式。
4.如果当前字符是(左括号,将其压入运算符栈。
5.如果当前字符为运算符,则
5.1.当运算符栈为空,则将其压入运算符栈。
5.2.当此运算符的优先级高于栈顶元素的时候,则将此运算符压入运算符栈;否则,弹出栈顶运算符到后缀表达式,并且将当前运算符压栈。回到步骤2.
6.如果当前字符是)右括号,反复将栈顶元素弹出到后缀表达式,直到栈顶元素是左括号(为止,并将左括号从栈中弹出丢弃。
7.如果读取还未完成,回到步骤2.
8.如果读取完成,则将栈中剩余的运算符依次弹出到后缀表达式。
我们再来看看后缀表达式怎样求值的:
从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 op 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果。
例如后缀表达式“3 4 + 5 × 6 -”:
(1) 从左至右扫描,将3和4压入堆栈;
(2) 遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素,注意与前缀表达式做比较),计算出3+4的值,得7,再将7入栈;
(3) 将5入栈;
(4) 接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
(5) 将6入栈;
(6) 最后是-运算符,计算出35-6的值,即29,由此得出最终结果。
前缀的转换和后缀的转换的比较:
| 中缀转前缀 | 中缀转后缀 |
栈 | 操作符栈 | 操作符栈 |
扫描顺序 | 从右到左 | 从左到右 |
遇到操作数 | 直接归入 | 直接归入 |
遇到右括号 | 直接入栈 | 将栈中操作符依次弹栈,归入,直至遇到左括号,将左括号弹栈,处理完毕 |
遇到左括号 | 将栈中操作符依次弹栈,归入,直至遇到右括号,将右括号弹栈,处理完毕 | 直接入栈 |
遇到其他操作符 | 检测栈顶操作符优先级与当前操作符优先级关系,如果栈顶大于当前,则出栈,归入,直至栈顶小于等于当前,并将当前操作符入栈 | 检测栈顶与当前优先级关系,如果栈顶大于等于当前则出栈,归入,直至栈顶小于当前,并将当前操作符入栈 |
操作符栈中的优先级 | 从栈底到栈顶操作优先级:非递减。即:栈顶可以大于或等于下面的 | 从栈底到栈顶优先级:递增。即:栈顶必须大于下面的 |
是否翻转 | 翻转 | 无需翻转 |
中缀表达式怎样转化为前缀表达式?
1.初始化运算符栈。
2.从算数表达式输入的字符串中依次从右向左每次读取一个字符。
3.如果当前字符是操作数,直接填写到前缀表达式。
4.如果当前字符是)右括号,将其压入运算符栈。
5.如果当前字符为运算符,则
5.1.当运算符栈为空,则将其压入运算符栈。
5.2.当此运算符的优先级高于或等于栈顶元素的时候,则将此运算符压入运算符栈;否则,弹出栈顶运算符到前缀表达式,并且将当前运算符压栈。回到步骤2.
6.如果当前字符是(左括号,反复将栈顶元素弹出到前缀表达式,直到栈顶元素是右括号)为止,并将右括号从栈中弹出丢弃。
7.如果读取还未完成,回到步骤2.
8.如果读取完成,则将栈中剩余的运算符依次弹出到前缀表达式。
9.翻转
例如,将中缀表达式“(2+3)×4”转换为前缀表达式的过程如下:
扫描元素 | 栈底---栈顶 | 解释说明 | 前缀表达式 |
4 | NULL | 数字直接加入前缀表达式 | 4 |
* | * | 运算符栈为空,则将其压入运算符栈(5.1) | 4 |
) | ) | )的优先级小于*,所以将 * 弹出并将 | 4* |
3 | ) | 数字直接加入前缀表达式 | 4*3 |
+ | )+ | + 的优先级),将 + 压入运算符栈 | 4*3 |
2 | )+ | 数字直接加入前缀表达式 | 4*32 |
( | NULL | 反复将栈顶元素弹出到前缀表达式,直到栈顶元素是右括号)为止,并将右括号从栈中弹出丢弃 | 4*32+ |
因此,前缀表达式为: + 2 3 * 4;