python中缀转后缀_中缀表达式转后缀表达式Python

本文介绍了如何理解中缀表达式转后缀表达式的过程,包括算法的推导和优化。通过举例和分析,阐述了在不转换为全括号表达式的情况下,如何直接对中缀表达式进行转换,使用栈来处理操作符的优先级问题,最后给出Python实现代码。
摘要由CSDN通过智能技术生成

中缀表达式转后缀表达式参考的文章就是直接给出了算法,但是算法如何推导出来的还没有弄明白,简单记录下我自己的理解,强行解释一下。

后缀表达式就是操作符再操作数的后面,并且计算机能够根据简单的优先级就能进行运算。之前介绍手动形式转换中缀表达式的时候,首先需要把括号按照计算顺序添加完整,形成全括号表达式。如((a+b)*c),然后再向外层移动。可以看出来最终的结果ab+c*,操作数的相对位置是没有改变的。而操作符是仅仅跳出了本层括号。因此对于操作数,可以直接按原顺序排放,对于操作符,先保存起来,(当然,括号也要保存起来),如果遇到右括号,就把之前的操作符取出来放到当前操作数的后面。这样就相当于将操作符跳出了括号。

因为我们遇到的都是中缀表达式,而不是全括号表达式,而且如果计算机转换成后缀表达式,那样会得不偿失,那么能否不需要全括号表达式呢?(原来中缀表达式就有的是不可能去掉的,因为会改变原有的优先级,只能是在不改原意的基础上进行去掉括号)

其实也可以不用转换成全括号表达式,对于最外面的一层括号,不用加上也行。只需要最后扫描结束时,把目前剩余的保存的操作符取出来放到操作数后面即可。

那么对于里面的括号呢?如果是(a+b+c)*d这种情况呢?它的全括号表达式是(((a+b)+c)*d),去掉了最外层的括号是((a+b)+c)*d,看看能否去掉a+b的括号。去掉后是(a+b+c)*d,按照上述步骤进行转换,即abc++d*,显然这样是不对的(不过按照后缀表达式的求值计算结果是对的,但是不能逆推成中缀表达式,所以是不对的),正确答案是ab+c+d*,显然a+b+c中间也是有“优先级”的(尽管计算结果一样),第一个加号比第二个加号的优先级要高。难道就不能去掉括号吗?根据结果逆向看一下,a和b的加号要比c的加号早一步出来,实际上式遇到c的加号时出来的(因为如果不出来,那么下一步遇到c,c一定就出来了)。所以想一下,应该是c的加号没有a和b的加号的优先级高,所以a和b的加号要提前出来(而不用等到右括号),再存储当前操作符。

用一个例子验证一下(a*b+c)*d,先按照最开始的说法转换,即abc*+d*,肯定都是不对的。然后按照上一步的转换,ab*c+d*,可以看出来这种情况是对的。应该能认为上一步的假设是对的。

那么如果是 (a+b*c)*d 这种情况呢,如果按照最开始的说法,就是abc+*d*了,这结果显然是不对的。因为*号比+号的优先级高,所以遇到*时,+号不用出来,而*号需要先存储起来。操作符那么取出来的顺序是什么样子的呢?因为*的优先级高,所以括号内读取结束时,*需要先做。可以想象,目前存储操作符的时候,只有当前操作符的优先级比已经存储的操作符的优先级高时才会存储,否则就会先取出再存入(见上一步优化)。所以存储的操作符顺序优先级是越来越高(随着读取的进行),因为越往后读取,肯定是遇到的是最近的一个操作符,而最近的操作符优先级又最高,所以可以断定,取操作符的时候是逆序的,因此可以用栈来实现所以可以验证全括号表达式,结果应该是abc*+d*。这也进一步验证了上面的优化是正确的。

总结来说,程序就是可以不用先转换成全括号表达式,直接对中缀表达式进行转换:遇到数字就直接写。

遇到原有的左括号就存储(入栈)。

遇到操作符先与已经存储的操作符进行优先级比较,如果比已有的优先级高就存储(入栈),如果小于等于原有的操作符优先级,就把原有的取出来(弹栈),再把当前操作符与新的栈顶进行优先级比较,重复上述步骤,直到存储当前操作符。

遇到右括号就把栈内所有的操作符取出来。

读取结束后,把栈内剩余的操作符取出来。结束

基本上,就是这个步骤了。代码如下。def infixToPostfix(infixexpr):

# 注意表达式里面的每个元素都要用空格隔开,便于后续的分割判断

# 定义优先级

prec = {}

prec['*'] = 3

prec['/'] = 3

prec['+'] = 2

prec['-'] = 2

prec['('] = 1

opStack = Stack()  # 用于保存操作符

postfixList = []   # 用于存储临时转换结果

tokenList = infixexpr.split()

for token in tokenList:

# 这里为了表示通用性,用字母表示一般的表达式

# 判断一般元素

if token in 'ABCDEFGHIJKLMNOPQRRSTUVWXYZ' or token in '0123456789':

postfixList.append(token)

# 判断左括号

elif token == '(':

opStack.push(token)

# print(opStack.peek())

# 判断右括号

elif token == ')':

topToken = opStack.pop()

while topToken != '(':

postfixList.append(topToken)

topToken = opStack.pop()

# 判断操作符

else:

while (not opStack.isEmpty()) and (prec[opStack.peek()] >= prec[token]):

postfixList.append(opStack.pop())

opStack.push(token)

# 遍历结束,最后取出所有操作符

while not opStack.isEmpty():

postfixList.append(opStack.pop())

return ' '.join(postfixList)

作者:qq_42907161

链接:https://blog.csdn.net/qq_42907161/article/details/108048932

来源:CSDN

著作权归作者所有,转载请联系作者获得授权,切勿私自转载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值