前缀、中缀和后缀表达式
本页博客参考:https://www.cnblogs.com/zzliu/p/10801113.html、百度百科
概述
前缀、中缀、后缀表达式是对表达式的不同记法,其区别在于运算符相对于数字的位置不同,前缀表达式的运算符位于操作数之前,中缀和后缀同理
如:
中缀表达式:1 + (2 + 3) × 4 - 5
前缀表达式:- + 1 × + 2 3 4 5
后缀表达式:1 2 3 + 4 × + 5 -
中缀表达式是人们最常用的算术表示方法,人脑很容易理解,但对计算机来说很复杂,因为要判断计算的优先级太过繁琐。对计算机来说,计算前缀或后缀表达式的值非常简单。
中缀转换为前缀、后缀
以1+(2+3)*4-5为例
转为前缀:
先根据计算的优先级加上括号。
然后将运算符从优先级最低的括号移到该括号外,并删去括号
- ((1+((2+3)×4))-5)
- -(1+((2+3)×4))5
- -+1((2+3)×4)5
- -+1×(2+3)45
- -+1×+2345
或 先根据计算的优先级加上括号,然后将每个运算符移到其所在最内部的括号前面,最后一次性删除括号
- ((1+((2+3)×4))-5)
- -(+(1×(+(23)4))5)
- -+1×+2345
转为后缀:
同理,也是先加上括号,然后将运算符移动到其所在最内部的括号后面,删除括号
- ((1+((2+3)×4))-5)
- ((1((23)+4)×)+5)-
- 123+4×+5-
前中后缀在计算机中的计算与转换
前缀计算
- 从右至左扫描表达式
- 遇到数字时,将数字压栈,遇到运算符时,弹出栈顶的两个数,计算并将结果入栈
- 重复2直到表达式最左端,最后运算得出的值即为表达式的结果
例:
计算前缀表达式的值:- + 1 × + 2 3 4 5
- 从右至左扫描,将5,4,3,2压入堆栈;
- 遇到+运算符,弹出2和3(2为栈顶元素,3为次顶元素),计算2+3的值,得到5,将5压入栈;
- 遇到×运算符,弹出5和4,计算5×4的值,得到20,将20压入栈;
- 遇到1,将1压入栈;
- 遇到+运算符,弹出1和20,计算1+20的值,得到21,将21压入栈;
- 遇到-运算符,弹出21和5,计算21-5的值,得到16为最终结果
后缀计算
与前缀表达式类似,只是顺序是从左至右:
- 从左至右扫描表达式
- 遇到数字时,将数字压栈,遇到运算符时,弹出栈顶的两个数,计算并将结果入栈
- 重复2直到表达式最右端,最后运算得出的值即为表达式的结果
示例:
计算后缀表达式的值:1 2 3 + 4 × + 5 -
- 从左至右扫描,将1,2,3压入栈;
- 遇到+运算符,3和2弹出,计算2+3的值,得到5,将5压入栈;
- 遇到4,将4压入栈
- 遇到×运算符,弹出4和5,计算5×4的值,得到20,将20压入栈;
- 遇到+运算符,弹出20和1,计算1+20的值,得到21,将21压入栈;
- 遇到5,将5压入栈;
- 遇到-运算符,弹出5和21,计算21-5的值,得到16为最终结果
代码实现:点击查看
中缀转换为前缀(百度百科)
转换算法
(1) 首先构造一个运算符栈(也可放置括号),运算符(以括号为分界点)在栈内遵循越往栈顶优先级不降低的原则进行排列。
(2)从右至左扫描中缀表达式,从右边第一个字符开始判断:
如果当前字符是数字,则分析到数字串的结尾并将数字串直接输出。
如果是运算符,则比较优先级。如果当前运算符的优先级大于等于栈顶运算符的优先级(当栈顶是括号时,直接入栈),则将运算符直接入栈;否则将栈顶运算符出栈并输出,直到当前运算符的优先级大于等于栈顶运算符的优先级(当栈顶是括号时,直接入栈),再将当前运算符入栈。
如果是括号,则根据括号的方向进行处理。如果是向右的括号,则直接入栈;否则,遇向左的括号前将所有的运算符全部出栈并输出,遇右括号后将向左、向右的两括号一起出栈(并不输出)。
(3) 重复上述操作(2)直至扫描结束,将栈内剩余运算符全部出栈并输出,再逆缀输出字符串。中缀表达式也就转换为前缀表达式了。
实例分析
将中缀表达式“1+((2+3)*4)-5”转换为前缀表达式。
中缀表达式 | 前缀表达式 | (栈尾)运算符栈(栈顶) | 说明 |
---|---|---|---|
5 | 5 | 空 | 5,是数字串直接输出 |
- | 5 | - | -,栈内无运算符,直接入栈 |
) | 5 | -) | ),直接入栈 |
4 | 5 4 | -) | 4,是数字串直接输出 |
* | 5 4 | -)* | *,栈顶是括号,直接入栈 |
) | 5 4 | - ) * ) | ),直接入栈 |
3 | 5 4 3 | - ) * ) | 3,是数字串直接输出 |
+ | 5 4 3 | - ) * ) + | +,栈顶是括号,直接入栈 |
2 | 5 4 3 2 | - ) * )+ | 2,是数字串直接输出 |
( | 5 4 3 2+ | - ) * | (,与栈里最后一个)抵消,并释放它们之间的+ |
( | 5 4 3 2+* | - | (,方法与上类同,请参考下一目录 |
+ | 5 4 3 2+* | -+ | +,优先级大于等于栈顶运算符,直接入栈 |
1 | 5 4 3 2+*1 | -+ | 1,是数字串直接输出 |
空 | 5 4 3 2+*1± | 空 | 扫描结束,将栈内剩余运算符全部出栈并输出 |
空 | - + 1 * + 2 3 4 5 | 空 | 逆缀输出字符串 |
中缀转换为后缀(百度百科)
算法实现
将一个普通的中缀表达式转换为逆波兰表达式的一般算法是:
首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为存放结果(逆波兰式)的栈S2(空栈),S1栈可先放入优先级最低的运算符#,注意,中缀式应以此最低优先级的运算符结束。可指定其他字符,不一定非#不可。从中缀式的左端开始取字符,逐序进行如下步骤:
(1)若取出的字符是操作数,则分析出完整的运算数,该操作数直接送入S2栈。
(2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符(不包括括号运算符)优先级高于S1栈栈顶运算符(包括左括号)优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符(包括左括号)低于(不包括等于)该运算符优先级时停止弹出运算符,最后将该运算符送入S1栈。
(3)若取出的字符是“(”,则直接送入S1栈顶。
(4)若取出的字符是“)”,则将距离S1栈栈顶最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
(5)重复上面的1~4步,直至处理完所有的输入字符。
(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。
完成以上步骤,S2栈便为逆波兰式输出结果。不过S2应做一下逆序处理。便可以按照逆波兰式的计算方法计算了!
实例分析
下面以(a+b)*c为例子进行说明:
(a+b)c的逆波兰式为ab+c,假设计算机把ab+c按从左到右的顺序压入栈中,并且按照遇到运算符就把栈顶两个元素出栈,执行运算,得到的结果再入栈的原则来进行处理,那么ab+c的执行结果如下:
1)a入栈(0位置)
2)b入栈(1位置)
3)遇到运算符“+”,将a和b出栈,执行a+b的操作,得到结果d=a+b,再将d入栈(0位置)
4)c入栈(1位置)
5)遇到运算符“”,将d和c出栈,执行dc的操作,得到结果e,再将e入栈(0位置)
经过以上运算,计算机就可以得到(a+b)*c的运算结果e了。