前缀表达式,中缀表达式,后缀表达式的一点微小理解

2 篇文章 0 订阅

中缀表达式

    中缀即我们平时用的数学表达式,其递归定义为中缀表达式 运算符 中缀表达式。举例:1+2,(1+2)*(3+4).这种表达式便于直观理解但是不方便计算机计算。后来有波兰人发明了前缀,后缀表达式。前缀表达式也叫波兰式,后缀表达式也叫逆波兰式。前后缀表达式经常作为栈在优先级的应用的例题。

前缀表达式

    前缀表达式递归定义为 运算符 前缀表达式 前缀表达式

前缀求值

    前缀计算方式即将运算符最右边两个放一起计算。
例题1:中缀表达式:1+((2+3)*4)-5,其对应前缀为- + 1 * + 2 3 4 5.前缀求值方式为每次取两个数字进行计算。具体如下(声明两个stack, s1和s2)

s1s2说明
- + 1 * + 2 3 4 5初始
- + 1 * + 2 3 45
- + 1 * + 2 34 5
- + 1 * + 23 4 5
- + 1 * +2 3 4 5
- + 1 *5 4 52 3出栈,做加法再push回去
- + 120 55 4出栈,做乘法再push回去
- +1 20 5
-21 520 1出栈,做加法再push回去
1621 5出栈,做加法再push回去

最后结果16.
可见前缀表达式通过栈保证每次都是当前优先级最高的两个做运算,也可以理解为保证先计算当前子前缀表达式。py代码如下:

def calPre(number):
    stack = []
    while number:
        if number[-1].isdigit():
            stack.append(int(number[-1]))
            number.pop()
        else:
            a = stack[-1]
            b = stack[-2]
            stack.pop()
            stack.pop()
            if number[-1] == '+':
                stack.append(a+b)
            elif number[-1] == '-':
                stack.append(a-b)
            elif number[-1] == '*':
                stack.append(a*b)
            else:
                stack.append(a/b)
            number.pop()
    return stack[0]

中缀变前缀

    那么先问问题来了,怎样将中缀变前缀?流程如下(摘抄自https://blog.csdn.net/idestina/article/details/81705516):
1.初始化两个栈:运算符栈S1和储存中间结果的栈S2;
2.从右至左扫描中缀表达式;
3.遇到操作数时,将其压入S2;
4.遇到运算符时,比较其与S1栈顶运算符的优先级:
  4.1. 如果S1为空,或栈顶运算符为右括号“)”,则直接将此运算符入栈;(右括号出现为了等待左括号,另外如果栈顶是右括号,此时开始计算子缀表达式)
  4.2. 否则,若优先级比栈顶运算符的较高或相等,也将运算符压入S1;
  4.3. 否则,将S1栈顶的运算符弹出并压入到S2中,再次转到(4-1)与S1中新的栈顶运算符相比较;(只有当 当前运算符级别比栈顶的低时才把栈顶的弹出,这样保证低级别尽可能留在最后计算,这句话纯属个人理解)
5.遇到括号时:
  5.1. 如果是右括号“)”,则直接压入S1;
  5.2.如果是左括号“(”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到右括号为止,此时将这一对括号丢弃;(一对括号内部是一个子表达式,也是一个子前缀表达式,虽然物理上是一串字符串,但是逻辑上就是一个数字因此需要将其算完)
6.重复步骤(2)至(5),直到表达式的最左边;
7.将S1中剩余的运算符依次弹出并压入S2;
8.依次弹出S2中的元素并输出,结果即为中缀表达式对应的前缀表达式。
这里边最关键的是栈的应用,如何通过栈安排好不同优先级的运算符。

例题2:已知中缀表达式:1+((2+3)*4)-5 求前缀表达式。

当前符号s1(符号栈)s2(暂存结果)说明
55
--5符号栈空,直接push进去
))-5)直接push进去
4)-4 5)直接push进去
**)-4 5栈顶是右括号,*直接push进去
))*)-4 5)直接push进去
3)*)-3 4 53直接push进去
++)*)-3 4 5+直接push进去
2+)*)-2 3 4 52 直接push进去
(*)-+ 2 3 4 5遇到(,就把符号栈依次出栈直到遇到),)丢弃
(-* + 2 3 4 5再次遇到(,就把符号栈依次出栈直到遇到),)丢弃
+±* + 2 3 4 5栈顶优先级不低于+ 直接入栈
1±1* + 2 3 4 51入栈
-+1* + 2 3 4 5剩余依次入栈

另外如果仅仅为了手工生成前缀,可以这样做:1+((2+3)*4)-5
还是从右往左,遇到第一个符号是-,可以把中缀表达式分成两个部分:
1+((2+3)*4)-5,那么其前缀表达式为 :
-①1+((2+3)*4)②5
下一步是把①②分别转化成中缀表达式,②不用转,直接看①
①可以写成:
+③1 ④((2+3)*4))
之后每一步如法炮制……
下面是算法的代码实现:

level = {'+':0,'-':0,'*':1,'/':1,'(':2,')':2}
def midToPre(str):
    symbol,number = [],[]

    for i in range(len(str)-1,-1,-1):
        s = str[i]
        if s.isdigit():
            number.append(s)
        else:
            if not symbol or s == ')' or symbol[-1] == ')':#左括号或者symbol空直接入栈
                symbol.append(s)
            elif s == '(':
                while symbol[-1] != ')':
                    number.append(symbol[-1])
                    symbol.pop()
                symbol.pop()
            else:
                while symbol and level[s] < level[symbol[-1]]:
                    number.append(symbol[-1])
                    symbol.pop()
                symbol.append(s)
    while symbol:
        number.append(symbol[-1])
        symbol.pop()
    number.reverse()
    return number

前缀变中缀

前缀变中缀的过程类似前缀求值计算。每次弹出两个,当当前运算符高于上次运算符时加上括号。
例题:-+1* + 2 3 4 5 变中缀

当前符号stack说明
55
44 5
33 4 5
22 3 4 5
+2+3 4 5
*(2+3)*4 5*高于+,加上括号
11 (2+3)*4 5
+1+(2+3)*4 5
-1+(2+3)*4 - 5

代码如下:

def preToMid(preList):
    stack = []
    last = ''
    for i in range(len(preList)-1,-1,-1):
        s = preList[i]
        if s.isdigit():
            stack.append(s)
        else:
            if last != '' and level[s] > level[last]:
                stack[-1] = ')'+stack[-1]+'('#最后要翻转
            a = stack[-1]
            b = stack[-2]
            stack.pop()
            stack.pop()
            stack.append(b+s+a)
            last = s
    return stack[0][::-1]

后缀表达式

后缀求值

    后缀表达式顾名思义,运算符在 后边,定义为 后缀表达式 运算符 后缀表达式。例如:1+((2+3)×4)-5的后缀表达式为1 2 3 + 4 × + 5 -。这个求值和前缀类似 ,不再赘述。

中缀变后缀

    
1.初始化两个栈:运算符栈S1和储存中间结果的栈S2;
2.从左至右扫描中缀表达式;
3.遇到操作数时,将其压入S2;
4.遇到运算符时,比较其与S1栈顶运算符的优先级:
  4.1. 如果S1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
  4.2. 否则,若优先级比栈顶运算符的较高(不含 相等),也将运算符压入S1;
  4.3. 否则,将S1栈顶的运算符弹出并压入到S2中,再次转到(4-1)与S1中新的栈顶运算符相比较;(只有当 当前运算符级别比栈顶的低时才把栈顶的弹出,这样保证低级别尽可能留在最后计算,这句话纯属个人理解)
5.遇到括号时:
  5.1. 如果是左括号“(”,则直接压入S1;
  5.2.如果是右括号“)”,则依次弹出S1栈顶的运算符,并压入S2,直到遇到右括号为止,此时将这一对括号丢弃;
6.重复步骤(2)至(5),直到表达式的最左边;
7.将S1中剩余的运算符依次弹出并压入S2;
8.依次弹出S2中的元素并输出,结果即为中缀表达式对应的前缀表达式。
注意与前缀的区别。

后缀变中缀

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值