目录
一. 前缀表达式与后缀表达式
二. 中缀表达式转后缀表达式的手算方法
三. 后缀表达式的手算方法
四. 后缀表达式的机算方法
五. 中缀表达式转前缀表达式的手算方法
六. 前缀表达式的机算方法
七. 中缀表达式转后缀表达式的机算方法
八. 中缀表达式的机算
让我们从大家熟悉的表达式说起:((15÷(7 -(1 +1))) × 3)-(2 +(1 +1))。表达式由三个部分组成:操作数、运算符、界限符。其中界限符不可省略,它反映了运算的先后顺序。
某波兰数学家就想:我们能否不用界限符也可以无歧义的表达运算顺序?答案显然是可以的,这就是“波兰表达式”(前缀表达式)和“逆波兰表达式”(后缀表达式)。
前缀表达式:二目运算符+操作数1+操作数2;后缀表达式:操作数1+操作数2+二目运算符
例如:
中缀表达式 | 前缀表达式 | 后缀表达式 |
a+b | +ab | ab+ |
a+b-c | -+abc | ab+c- |
a+b-c*d | -+ab*cd | ab+cd*- |
需要说明的是,由于确定中缀表达式的各个运算符的运算顺序不同(例如第3个既可以先算a+b也可以先算c*d),同一中缀表达式转化的前缀表达式和后缀表达式也可能不同。
例如:前面的中缀表达式各运算符顺序确定如下:
在后缀表达式中,1 1 +先作为一个操作数,然后用7减去,就是7 1 1 + -,再用15除,就是15 7 1 1 + - /,以此类推。
再如,对同一中缀表达式确定不同的运算符顺序:
客观来看两种都正确。但是如果用计算机实现转换,算法需要有确定性,显然前面一种转化运算符的顺序就是运算顺序。更优。
那么如何保证对中缀表达式计算得到后缀表达式的时候,运算符的顺序就是运算顺序呢?显然我们要在确定中缀表达式的运算符运算顺序时不要FreeStyle。这里应当采用所谓“左优先”原则,即:要左边的运算符能先计算,就优先算左边的。
例如:对下面的中缀表达式,确定运算符顺序如下:
方法:从左往右扫描,每遇到一个运算符,就让运算符前面最近的两个操作数执行对应运算,合体为一个操作数。应当注意:两个操作数的左右顺序问题。
后缀表达式的特点是:最后出现的操作数被最先计算。
前面说到后缀表达式的特点是:最后出现的操作数被最先计算。这就很完美符合栈的后进先出的特点。接下来讲如何利用栈实现机算。这里栈是操作数栈
以(三)中的第2张图为例:A入栈-B入栈-扫描到+,弹出A和B,执行完A+B后把(A+B)压入栈内-C入栈-D入栈-扫描到*,弹出C和D,执行C*D中把(C*D)压入栈内-E入栈-扫描到/,弹出E和(C*D)【注意先出栈的是右操作数】,执行(C*D)/E后把结果压入栈内-扫描到—,把(C*D)/E和(A+B)弹出,计算(A+B)-(C*D)/E后压入栈内-F入栈-扫描到+,弹出F和(A+B)-(C*D)/E,执行完(A+B)-(C*D)/E+F后压入栈内-扫描结束,这个时候栈内只剩一个元素,它就是最终结果(A+B)-(C*D)/E+F。
相似的,为了得到唯一表达式,采用“右优先”原则:只要右边的运算符能先计算,就优先算右边的。例如下面的表达式,选择右面的计算顺序可以得到倒序的运算顺序。
此部分和(四)类似,只不过是从右往左扫描:
初始化一个栈,用于保存暂时还不能确定运算顺序的运算符。从左到右处理各个元素,直到末尾。可能遇到三种情况:
按上述方法处理完所有字符后,将栈中剩余运算符依次弹出,并加入后缀表达式。
仍然以(三)中的第2张图为例:初始化一个用来存放运算符的栈。
从前到后扫描中缀表达式:A直接加入后缀表达式—+号入栈—B直接加入后缀表达式—扫描到-,+从栈弹出加入后缀表达式,然后-入栈—C直接加入后缀表达式—*入栈—D直接加入后缀表达式—扫描到/,*从栈弹出加入后缀表达式,然后/入栈—E直接加入后缀表达式—扫描到+,/和-依次从栈弹出并加入后缀表达式,然后+入栈—F直接加入后缀表达式—扫描结束,此时栈内只有一个+,把+输出加入到后缀表达式中。
我们再看一个带括号的中缀表达式:A直接加入后缀表达式—+号入栈—B直接加入后缀表达式—*入栈—(直接入栈—C直接加入后缀表达式—扫描到-,此时运算符栈顶元素是(,所以直接把-入栈—D直接加入后缀表达式—扫描到),此时栈底到栈顶有+,*,(,-,依次从栈顶全部弹出【(不进入后缀表达式】—“-”号入栈—E直接加入后缀表达式—扫描到/,入栈—F直接加入后缀表达式—扫描结束,此时栈内有-,/,依次输出/和-,结束。
其实就是(七)和(四)的结合。
仍然以(三)中的第2张图为例:A入操作数栈—+入运算符栈—B入操作数栈—扫描到-,弹出运算符等级相同的+,并从操作数栈弹出A和B,计算A+B后压回操作数栈,最后-号入运算符栈—C入操作数栈—*入运算符栈—D入操作数栈—扫描到/,弹出运算符*,同时弹出C和D,计算C*D后压回操作数栈,最后把/压入运算符栈—E入操作数栈—扫描到+,/和-依次弹出。弹出/时计算C*D/E,压回操作数栈中,然后弹出-时计算A+B-C*D/E,压回操作数栈中,最后把+压入运算符栈—F入操作数栈—扫描结束,把运算符栈清空,每弹出一个运算符弹出两个操作数,这样就是A+B-C*D/E+F。