一、问题描述
在计算机计算一个算数表达式的时候,首先是将我们熟悉的中缀表达式转化后缀表达式,再基于后缀表达式进行计算得到结果。
中缀表达式: 9+(3-1)*3+10/2,是人所熟悉并常用的表达式形式。
后缀表达式: 9 3 1 - 3 * + 10 2 / + ,是不包含括号,运算符在两个运算对象后面的表达式,计算机基于对堆栈的处理能够更容易的计算后缀表达式得到结果。
二、中缀表达式转化为后缀表达式
1、首先初始化一个空的字符串(String)和堆栈(Stack)。
2、将中缀表达式中的数字和运算符(包括加减乘除及左右括号)分割成单个字符存进一个新的数组中,比如上面的中缀表达式就存为:9 + ( 3 - 1 ) * 3 + 10 / 2 。
3、遍历这个数组,操作数直接放进String中,运算符则存放在堆栈中。
3.1、如果是空栈,运算符直接进栈。
3.2、如果栈不为空,将当前遍历到的运算符与栈顶运算符做优先级比较,如果栈顶运算符为左括号或优先级低于当前运算符,则当前运算符入栈,否则栈顶运算符弹出栈并连接在String后,当前运算符再与弹栈后的栈顶运算符做比较,直到栈顶运算符低于当前运算符的优先级或遇到左括号,将当前运算符入栈;当前运算符若是右括号,则将栈顶运算符依次弹出并依次连接到String后,直到遇到左括号,并将左括号弹出(但是不连接在String后的,注意后缀表达式中是没有括号的)。
4、如果中缀表达式遍历完毕后栈中还有运算符则将栈中剩下的运算符依次弹出并连接在String后,最终得到的字符串String就是后缀表达式。
三、计算后缀表达式
1、初始化一个栈用来存放操作数,然后定义一个变量存放最后的结果。
2、遍历后缀表达式,遍历到操作数则依次进栈,遍历到运算符的时候将栈顶操作数弹出(假设赋给变量a),再弹出一个栈顶操作数(假设赋给变量b),用后者对前者做该运算符对应的运算(假设遍历到的运算符为+,则做计算b+a),然后将计算结果入栈。
3、以此类推,最终遍历得到的结果即为运算结果。
四、python代码
# 中缀表达式
infix_expression = '9+(3-1)*3+10/2'
# 优先级列表
priority1 = ['*', '/']
priority2 = ['+', '-']
# 字符是否使用列表
useable = [True for i in range(len(infix_expression))]
# 初始化堆栈和后缀表达式
stack = []
postfix_expression = []
for i in range(len(infix_expression)):
# 防止操作数字符重复使用
if useable[i] is True:
# 操作数字符直接加入堆栈
if infix_expression[i].isdigit():
operand = [infix_expression[i]]
if i < len(infix_expression) - 1:
j = 1
# 将长度大于1的操作数作为整体加入堆栈
while (infix_expression[i + j].isdigit() or infix_expression[i + j] is '.'):
operand.append(infix_expression[i + j])
useable[i + j] = False
j += 1
if (i + j) == len(infix_expression):
break
operand = "".join(operand)
postfix_expression.append(operand)
else:
# 堆栈列表不为空
if len(stack):
# '('直接加入堆栈
if infix_expression[i] is '(':
stack.append(infix_expression[i])
# 处理处于优先级1的运算符
elif infix_expression[i] in priority1:
while(True):
if len(stack) == 0 or stack[-1] in priority2 or stack[-1] is '(':
stack.append(infix_expression[i])
break
else:
postfix_expression.append(stack.pop())
# 处理处于优先级2的运算符
elif infix_expression[i] in priority2:
while (True):
if len(stack) == 0 or stack[-1] is '(':
stack.append(infix_expression[i])
break
else:
postfix_expression.append(stack.pop())
# 处理')'
elif infix_expression[i] is ')':
while(stack[-1] != '('):
postfix_expression.append(stack.pop())
stack.pop()
# 堆栈列表为空,直接加入堆栈
else:
stack.append(infix_expression[i])
# 获得最终的后缀表达式
for i in range(len(stack)):
postfix_expression.append(stack.pop())
# 利用后缀表达式计算结果
for i in range(len(postfix_expression)):
if postfix_expression[i].isdigit():
stack.append(postfix_expression[i])
else:
oper1 = float(stack.pop())
oper2 = float(stack.pop())
if postfix_expression[i] == '+':
stack.append(oper2 + oper1)
elif postfix_expression[i] == '-':
stack.append(oper2 - oper1)
elif postfix_expression[i] == '*':
stack.append(oper2 * oper1)
elif postfix_expression[i] == '/':
stack.append(oper2 / oper1)
print('中缀表达式;', infix_expression)
print('后缀表达式:', " ".join(postfix_expression))
print('计算结果:', stack[0])
代码运行结果: