逆波兰式(Reverse Polish notation,RPN,或逆波兰记法),也叫后缀表达式(将运算符写在操作数之后)。而与之对应的是我们在数学中常见的 中缀表达式(既操作符在操作数中间)例如 12+23 就是典型的中缀式,而与之对应的逆波兰式则为12,13,+
将传统的中缀式转化为后缀式后,可以简化计算机的计算。将复杂表达式转换为可以依靠简单的操作得到计算结果的表达式。方便计算机编程实现,例如(a+b) * (c+d)转换为ab+cd+*,就避免了括号的运算,在编程和计算上就较少了逻辑判断与分支的处理。
(一). 逆波兰式的转换
首先创建两个空栈(Python中可用List实现栈的功能),stack_expr, stack_opr 分别来装操作数与操作符。从头开始遍历准备好的中缀式,按以下步骤进行转换: (注:此处本人将中缀式处理为List形式,以方便后续计算,读者可自行决定中缀式形式 )
附上本人处理后中缀式形式 : 2.0*(3.1+4.8)+5.0 ----> [2.0, '*', '(', 3.1, '+', 4.8, ')', '+', 5.0]
0、当前遍历到的字符记作Index
1、若index是数字, 将该index入栈stack_expr
2、若index是非数字:
2.1、是左括号, 将左括号入栈stack_opr
2.2、是右括号,将stack_opr中的操作符从栈顶依次出栈并入栈stack_expr, 直到遇到左括号终止操作(注意: 该左括号出栈stack_opr但不入栈stack_expr)这样就消除表达式中的括号消除了
2.3、若index是普通操作符(+ - * /)
2.3.1、 若stack_opr为空, 操作符入栈stack_opr
2.3.2、 如果stack_opr不空,将stack_opr栈顶操作符与index比较优先级:
2.3.2.1、若index的优先级高于stack_opr栈顶操作符的优先级,则index入栈 stack_opr
2.3.2.2、若index的优先级小于或者等于stack_opr栈顶操作符, stack_opr栈顶操作符出栈并入栈 stack_expr,直到index优先级高于stack_opr 的优先级,将index入stack_opr栈。(注:若stack_opr出栈时,将stack_opr出空后,index直接入栈即可)
3、中缀式遍历结束后如果stack_opr栈不为空,则依次将操作符出栈并入栈stack_expr
代码实现:
pat = ['+','-','*','/','(',')','%']
def reverse_polish(data):
stack_opr = list()
#数字栈
stack_expr = list()
#优先级
dicts = {
'+' : 1,
'-' : 1,
'*' : 2,
'/' : 2,
'(' : 0
}
global pat
for index in data:
#1.数字,进expr栈
if index not in pat:
stack_expr.append(index)
#2.非数字
else:
#2.1 opr栈空
if not stack_opr:
stack_opr.append(index)
#2.2 opr栈非空
else:
#2.2.1 index 是 左括号 ,入栈opr
if index == '(':
stack_opr.append(index)
#2.2.2 index 是右括号,将栈顶的操作符出opr栈,并入expr栈 ,直到遇到左括号
elif index ==')':
while True:
newdex = stack_opr.pop()
#2.2.2.1 newdex是操作符
if newdex != '(':
stack_expr.append(newdex)
#2.2.2.2 newdex 是左括号
else:
break
#2.2.3 index是普通操作符
else:
while True:
#2.2.3.0 opr栈空,则直接入栈
if not stack_opr:
stack_opr.append(index)
break
level_index = dicts[index]
level_opr = dicts[stack_opr[-1]]
#2.2.3.1 index 优先级 比 opr 栈顶优先级 高 ,index 入 opr栈
if level_index > level_opr:
stack_opr.append(index)
break
#2.2.3.2 index 优先级 比 opr 栈顶优先级 低或等于 , opr栈顶 出栈 并 入expr 栈,直到 index 优先级 高于 opr 栈顶优先级
else:
topdex = stack_opr.pop()
stack_expr.append(topdex)
#3. data 原表达式 已被遍历完,若opr 栈不为空,则依次出栈 进 expr栈
while True:
if len(stack_opr)!=0:
dex = stack_opr.pop()
stack_expr.append(dex)
else:
break
return stack_expr
(二). 逆波兰式的计算
相对于将中缀式转换为逆波兰式,逆波兰式的计算就简单多了只需如下几步即可:
建立一个一个数值栈stack_res(同样用List实现),用于存放中间数值以及计算结果
遍历转换好的逆波兰式:
1、如果遇到数字,入栈stack_res;
2、如果遇到运算符, 从stack_res中依次出栈两个数与 遇到的操作符进行计算即可,将结果压入stack_res栈中
3、 继续遍历下一个元素,直到结束;
代码实现
def compute(data):
stack_res = list()
global pat
for index in data:
#1 数字,进res栈
if index not in pat:
stack_res.append(index)
#2 运算符
else:
# 2.1 左右操作数
right_ops = stack_res.pop()
left_ops = stack_res.pop()
if index == '*':
res = left_ops*right_ops
stack_res.append(res)
#出数不能为零,需要抛异常进行处理
if index == '/':
res = left_ops/right_ops
if right_ops == 0:
raise Exception('Zero')
stack_res.append(res)
if index == '+':
res = left_ops+right_ops
stack_res.append(res)
if index == '-':
res = left_ops-right_ops
stack_res.append(res)
if len(stack_res) == 1:
return stack_res[0]