前缀、中缀、后缀表达式计算和转化算法详解

前缀、中缀和后缀表达式

本页博客参考: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. ((1+((2+3)×4))-5)
  2. -(1+((2+3)×4))5
  3. -+1((2+3)×4)5
  4. -+1×(2+3)45
  5. -+1×+2345

或 先根据计算的优先级加上括号,然后将每个运算符移到其所在最内部的括号前面,最后一次性删除括号

  1. ((1+((2+3)×4))-5)
  2. -(+(1×(+(23)4))5)
  3. -+1×+2345

转为后缀:

同理,也是先加上括号,然后将运算符移动到其所在最内部的括号后面,删除括号

  1. ((1+((2+3)×4))-5)
  2. ((1((23)+4)×)+5)-
  3. 123+4×+5-

前中后缀在计算机中的计算与转换

前缀计算

  1. 从右至左扫描表达式
  2. 遇到数字时,将数字压栈,遇到运算符时,弹出栈顶的两个数,计算并将结果入栈
  3. 重复2直到表达式最左端,最后运算得出的值即为表达式的结果

例:
计算前缀表达式的值:- + 1 × + 2 3 4 5

  1. 从右至左扫描,将5,4,3,2压入堆栈;
  2. 遇到+运算符,弹出2和3(2为栈顶元素,3为次顶元素),计算2+3的值,得到5,将5压入栈;
  3. 遇到×运算符,弹出5和4,计算5×4的值,得到20,将20压入栈;
  4. 遇到1,将1压入栈;
  5. 遇到+运算符,弹出1和20,计算1+20的值,得到21,将21压入栈;
  6. 遇到-运算符,弹出21和5,计算21-5的值,得到16为最终结果

后缀计算

与前缀表达式类似,只是顺序是从左至右:

  1. 从左至右扫描表达式
  2. 遇到数字时,将数字压栈,遇到运算符时,弹出栈顶的两个数,计算并将结果入栈
  3. 重复2直到表达式最右端,最后运算得出的值即为表达式的结果

示例:
计算后缀表达式的值:1 2 3 + 4 × + 5 -

  1. 从左至右扫描,将1,2,3压入栈;
  2. 遇到+运算符,3和2弹出,计算2+3的值,得到5,将5压入栈;
  3. 遇到4,将4压入栈
  4. 遇到×运算符,弹出4和5,计算5×4的值,得到20,将20压入栈;
  5. 遇到+运算符,弹出20和1,计算1+20的值,得到21,将21压入栈;
  6. 遇到5,将5压入栈;
  7. 遇到-运算符,弹出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了。

代码实现:点击查看

你可能感兴趣的:(JAVA,算法,数据结构,算法,java)