棧和佇列(二):棧的經典問題
阿新 • • 發佈:2020-10-16
引言
本節主要介紹棧的經典應用:
- 中綴表示式轉字尾表示式
- 字尾表示式的計算
- 括號問題
中綴表示式與字尾表示式
首先來介紹一下這兩種表示式:
- 中綴表示式:這名字看起來很專業,實際上它就是我們日常打草稿時所用的計算表示式,如'1+2×3/4+(2-1)='這樣的式子就是中綴表示式;但是中綴表示式不足以表示所有可能的運算順序。
- 字尾表示式:所有運算子都在運算物件之後,不需要引進括號,適合計算機處理;由於字首表示式被稱為波蘭表示式,因此後綴表示式也被稱為逆波蘭表示式。
那麼如何來進行表示式之間的轉換呢?
-
如果遇到運算物件,我們可以直接將其擴充套件到列表中;
-
如果遇到左括號或者運算子棧為空時,我們直接將其壓入棧;
-
如果遇到運算子號,那麼就比較棧頂符號和當前符號的優先順序,當棧頂符號優先順序高時則必須將其輸出,這樣操作符合運算邏輯;
-
只有遇到右括號時,左括號才可以彈出,雖然括號優先順序高,但是為了去掉括號,必須這麼做;
Python實現:
這裡為了簡化程式碼,不再專門為中綴表示式建立生成器,輸入的表示式引數均為有效的。
def infix_to_postfix(s): priority = {'(':1, '+':2, '-':2, '*':3, '/':3} signal = '()-+*/' tmp = [] # 運算子快取空間 exp = [] # 表示式 for x in s: if x not in signal: exp.append(x) elif len(tmp) == 0 or x == '(': tmp.append(x) elif x == ')': while len(tmp) > 0 and tmp[-1] != '(': exp.append(tmp.pop()) if len(tmp) == 0: raise SyntaxError('不存在對應的"("') tmp.pop() else: while len(tmp) > 0 and priority[tmp[-1]] >= priority[x]: exp.append(tmp.pop()) tmp.append(x) while len(tmp) > 0: if tmp[-1] == '(': raise SyntaxError('存在多餘的"("!') exp.append(tmp.pop()) return exp if __name__ == '__main__': # postfix = ['3', '5', '-', '6', '17', '4', '*', '+', '*', '3', '/'] # print(PostfixExpressionCounter(postfix)) # error = ['3', '5', '-', '6', '17', '4', '*', '+', '*', '3', '4'] # print(PostfixExpressionCounter(error)) infix = ['(', '3', '-', '5', ')', '*', '(', '6', '+', '17', '*','4', ')', '/', '3'] print(infix_to_postfix(infix))
字尾表示式的計算
計算字尾表示式的主要思想就是利用棧才快取運算物件,在遇到運算子時彈出運算物件進行計算,計算完成以後再次壓入棧。
Python實現:
為了讓函式更加穩健,筆者在這裡增加了結構判斷,如果計算結束後棧內元素個數不為1,那麼一定出現了表示式錯誤。
def PostfixExpressionCounter(s): nums = [] for i in s: if i not in '+-*/': nums.append(int(i)) else: num2 = nums.pop() num1 = nums.pop() if i == '-': nums.append(num1-num2) elif i == '+': nums.append(num1+num2) elif i == '/': nums.append(num1/num2) else: nums.append(num1*num2) if len(nums) == 1: return nums[0] raise SyntaxError('表示式結構錯誤!') if __name__ == '__main__': s = ['3', '5', '-', '6', '17', '4', '*', '+', '*', '3', '/'] print(PostfixExpressionCounter(s)) error = ['3', '5', '-', '6', '17', '4', '*', '+', '*', '3', '4'] print(PostfixExpressionCounter(error))
括號問題——有效括號判定
問題來源:
問題簡述:
判斷一個由括號組成的字串,是否為有效的括號組合(每一個左括號都有對應的右括號,且順序正確)。
問題分析:
由於括號存在巢狀,所以不能立即判斷左括號是否有對應的右括號存在,因此需要一個快取空間來儲存左括號。
Python實現:
class Solution:
def isValid(self, s: str) -> bool:
if len(s) % 2 != 0: return False
left, right = {'(': 1, '[': 2, '{':3}, {')': 1, ']': 2, '}':3}
stack = []
for i in range(len(s)):
if not stack:
stack.append(s[i])
continue
if left.get(stack[-1], -1) == right.get(s[i], -2):
stack.pop()
else:
stack.append(s[i])
return stack == []
參考資料
- 裘宗燕.資料結構與演算法——Python語言描述[M].北京:機械工業出版社,2015: 145-150。