1,逆波兰算法简介
假定给定一个只 包含 加、减、乘、除,和括号的算术表达式,你怎么编写程序计算出其结果?
问题是:在表达式中,括号,以及括号的多层嵌套 的使用,运算符的优先级不同等因素,使得一个算术表达式在计算时,运算顺序往往因表达式的内容而定,不具规律性。 这样很难编写出统一的计算指令。
使用逆波兰算法可以轻松解决这个问题。他的核心思想是将普通的中缀表达式转换为后缀表达式。
什么是中缀表达式?例如a+b,运算符在两个操作数的中间。这是我们从小学开始学习数学就一直使用的表达式形式。
什么是后缀表达式?例如a b + ,运算符在两个操作数的后面。后缀表达式虽然看起来奇怪,不利于人阅读,但利于计算机处理。
转换为后缀表达式的好处是:
1、去除原来表达式中的括号,因为括号只指示运算顺序,不是实际参与计算的元素。
2、使得运算顺序有规律可寻,计算机能编写出代码完成计算。
2,逆波兰算法原理
逆波兰算法的核心步骤就2个:
1、将中缀表达式转换为后缀表达式,例如输入的原始表达式是 3*(5+7) ,转换得到 3 5 7 + *
2、根据后缀表达式,按照特定的计算规则得到最终计算结果
下面详细介绍这个2步的操作。
中缀表达式转换为后缀表达式
你需要设定一个栈SOP,和一个线性表 L 。SOP用于临时存储运算符和左括号分界符( ,L用于存储后缀表达式。
遍历原始表达式中的每一个表达式元素
(1)如果是操作数,则直接追加到 L中。只有 运算符 或者 分界符( 才可以存放到 栈SOP中
(2)如果是分界符
Ⅰ 如果是左括号 ( , 则 直接压入SOP,等待下一个最近的 右括号 与之配对。
Ⅱ 如果是右括号),则说明有一对括号已经配对(在表达式输入无误的情况下)。不将它压栈,丢弃它,然后从SOP中出栈,得到元素e,将e依次追加到L里。一直循环,直到出栈元素e 是 左括号 ( ,同样丢弃他。
(3)如果是运算符(用op1表示)
Ⅰ如果SOP栈顶元素(用op2表示) 不是运算符,则二者没有可比性,则直接将此运算符op1压栈。 例如栈顶是左括号 ( ,或者栈为空。
Ⅱ 如果SOP栈顶元素(用op2表示) 是运算符 ,则比较op1和 op2的优先级。如果op1 > op2 ,则直接将此运算符op1压栈。
如果不满足op1 > op2,则将op2出栈,并追加到L,再试图将op1压栈,如果如果依然不满足 op1>新的栈顶op2,继续将新的op2弹出追加到L ,直到op1可以压入栈中为止。
也就是说,如果在SOP栈中,有2个相邻的元素都是运算符,则他们必须满足:下层运算符的优先级一定小于上层元素的优先级,才能相邻。
最后,如果SOP中还有元素,则依次弹出追加到L后,就得到了后缀表达式。
3,应用
请写一个整数计算器,支持加减乘除三种运算和括号。
输入 "1+2" 输出 3 输入 "(2*(3-4))*5" 输出 -10
python 代码实现:
class Solution: def __init__(self): self.Operator_priority = { "+": 0, "-": 0, "*": 1, "/": 1 } self.Operator = ["+", "-", "*", "/"] self.DemarcationSymbol = ["(", ")"] self.L = [] self.stack = [] def solve(self, s): self.infixToSuffix(s) return self.suffixToResult(self.L) def changeTypeofExpression(self, expression): temp_expression = [] temp_num = "" for exp in expression: if exp.isdigit(): temp_num += exp continue else: temp_expression.append(temp_num) temp_num = "" temp_expression.append(exp) temp_expression.append(temp_num) return temp_expression def infixToSuffix(self, expression): temp_expression = self.changeTypeofExpression(expression) for item in temp_expression: if item.isdigit(): self.L.append(item) elif item in self.Operator: # 判断是否是操作符 while len(self.stack) != 0 and self.stack[-1] in self.Operator and self.Operator_priority[item] <= self.Operator_priority[self.stack[-1]]: self.L.append(self.stack.pop()) self.stack.append(item) elif item in self.DemarcationSymbol: # 判断是否是分隔符 if item == "(": self.stack.append(item) elif item == ")": while len(self.stack) != 0 and self.stack[-1] != "(": self.L.append(self.stack.pop()) if len(self.stack) != 0: self.stack.pop() while len(self.stack) != 0: self.L.append(self.stack.pop()) def suffixToResult(self, suffix_expression): for item in suffix_expression: if item.isdigit(): # 如果是数字就添加到stack中去 self.stack.append(item) elif item in self.Operator: num1 = self.stack.pop() num2 = self.stack.pop() temp_value = self.Calculation(float(num2), float(num1), item) self.stack.append(temp_value) return self.stack.pop() def Calculation(self, num1, num2, op): if op == "+": return num1+num2 elif op == "-": return num1-num2 elif op == "*": return num1*num2 else: return num1/num2 if __name__ == "__main__": s = Solution() print(s.solve("(100+100)*100"))