中缀表达式求值python_逆波兰表达式的转化与求值(python实现)

目前,大多数编程语言都能直接计算类似于9 + ( 3 - 1 ) * 3 + 10 / 2这样的表达式,本文从数据结构的层次上讲解具体的实现算法,首先搞懂以下两个定义:

中缀表达式: 在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,这种表示法也称 为中缀表达式,简单来说,我们平常见到的运算表达式就叫中缀表达式;

后缀表达式: 又叫逆波兰表达式 ,不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则,如:(2 + 1) * 3 的后缀表达式为2 1 + 3 *

中缀表达式就不多介绍了,大家都比我还明白,那么看看逆波兰表达式是如何转化而来的,先给几个小例子热热身体 (a+b ---> a,b,+                   a+(b-c)*d ---> a,b,c,-,d,*,+                       a+(b-c) ---> a,b,c,-,+)

一、 将 中缀表达式s=“9 + ( 3 - 1 ) * 3 + 10 / 2”变为后缀表达式s_after = "9 3 1 - 3 * + 10 2 / +",具体的规则如下 :

首先维护两个空栈,(stack_exp)存逆波兰表达式,(stack_ops)暂存操作符,运算结束后stack_ops必为空循环遍历字符串(将表达式分为四种元素 1、数值; 2、操作符; 3、 左括号; 4、右括号),具体情况如下:

1、遇到数值, 将该值入栈stack_exp

2、遇到左括号, 将左括号入栈stack_ops

3、遇到右括号,将stack_ops中的操作符从栈顶依次出栈并入栈stack_exp, 直到第一次遇到左括号终止操作(注意: 该左括号出栈stack_ops但不入栈stack_exp)至此消除表达式中的一对括号

4、遇到四则运算操作符号(+ - * /)

4-1、 如果stack_ops为空, 操作符入栈stack_ops

4-2、 如果stack_ops不空,将stack_ops栈顶操作符与遍历到的操作符(op)比较:

4-2-1: 如果stack_ops栈顶操作符为左括或者op优先级高于栈顶操作符优先级, op入栈                                           stack_ops,当前遍历结束

4-2-2: 如果op优先级小于或者等于stack_ops栈顶操作符, stack_ops栈顶操作符出栈并入栈                                     stack_exp,重复4-1、 4-2直到op入栈stack_ops

5、字符串遍历结束后如果stack_ops栈不为空,则依次将操作符出栈并入栈stack_exp

代码实现(python版本)

# 运算规则,先乘除,后加减.

ops_rule = {

'+': 1,

'-': 1,

'*': 2,

'/': 2

}

def middle_to_after(s):

"""

中缀表达式转化后缀表达式.

:param s: 中缀表达式的字符串表示,本程序中采用操作符跟数值之间用空格分开,例如:

"9 + ( 3 - 1 ) * 3 + 10 / 2"

:return: 后缀表达式,数组的形式,每个数值或者操作符占一个数组下标.

"""

expression = []

ops = []

ss = s.split(' ')

for item in ss:

if item in ['+', '-', '*', '/']: # 操作符

while len(ops) >= 0:

if len(ops) == 0:

ops.append(item)

break

op = ops.pop()

if op == '(' or ops_rule[item] > ops_rule[op]:

ops.append(op)

ops.append(item)

break

else:

expression.append(op)

elif item == '(': # 左括号,直接入操作符栈

ops.append(item)

elif item == ')': # 右括号,循环出栈道

while len(ops) > 0:

op = ops.pop()

if op == '(':

break

else:

expression.append(op)

else:

expression.append(item) # 数值,直接入表达式栈

while len(ops) > 0:

expression.append(ops.pop())

return expression

二、将后缀表达式s_after = "9 3 1 - 3 * + 10 2 / +" 求值,具体的规则如下 :

初始化一个数值栈stack_value,用于存放中间数值以及计算结果

遍历s_after:

1、如果遇到数字,入栈stack_value;

2、如果遇到运算符, 从stack_value中依次出栈两个数(先出栈的在右, 后出栈的在左)连同遍历到的运算符组成二目运算,求值后将结果压栈stack_value;

3、 继续遍历下一个元素,直到结束;

遍历完后stack_value中的结果便是表达式的值

代码实现如下(python):

def expression_to_value(expression):

"""

:param expression: 后缀表达式的字符串表示,操作符跟数值间用空格分割,例如:

"9 3 1 - 3 * + 10 2 / +"

:return: 运算结果,一个值

"""

stack_value = []

for item in expression:

if item in ['+', '-', '*', '/']:

n2 = stack_value.pop() # 注意,先出栈的在操作符右边.

n1 = stack_value.pop()

result = cal(n1, n2, item)

stack_value.append(result)

else:

stack_value.append(int(item)) # 数值直接压栈.

return stack_value[0]

def cal(n1, n2, op):

if op == '+':

return n1 + n2

if op == '-':

return n1 - n2

if op == '*':

return n1 * n2

if op == '/':

return n1 / n2

到此为止,这个后缀表达式的转化以及求解介绍完了,不知道大家整明白了吗,可以结合代码仔细研究,另外,如果有哪位朋友发现此文有误,欢迎留言告知,更多好文章,敬请期待...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值