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"))