栈的实现与应用
一、棧的實現
- 方法一:就使用list即可
先進后出
- 方法二:定義Stack,抽象出棧
二、棧的應用
2.1平衡括號問題
#經典使用stack的場景:平衡括號問題 from stack import Stackdef is_balance(mystr):s = Stack()#默認是對稱的balance = Truefor item in mystr:if item == '(':s.push(item)elif item == ')':if s.isEmpty():#右括號多于左括號的情況balance = Falses.pop()if not s.isEmpty():#左括號多于右括號的情況balance = Falsereturn balanceif __name__ == '__main__':print(is_balance('((()))'))print(is_balance('(()'))2.2廣義的平衡問題
#經典使用stack的場景:平衡括號問題 from stack import Stackdef is_balance(mystr):s = Stack()#默認是對稱的balance = Truefor item in mystr:if item in sym_dict.keys():s.push(item)elif item in sym_dict.values():if s.isEmpty():#右括號多于左括號的情況balance = Falseelif sym_dict[s.peek()] == item:s.pop()if not s.isEmpty():#左括號多于右括號的情況balance = Falsereturn balanceif __name__ == '__main__':sym_dict = {'(': ')','{': '}','[': ']',} print(is_balance('{{([][])}()}'))print(is_balance('[{()]'))2.3 任意進制轉換問題
十進制轉換到其他進制時,存在取余最后求反的過程,這個求反過程如果利用stack這種數據結構,可以節省reverse(list)的O(n)操作!
from stack import Stack from functools import reducedef dec_to_any(num, base=2):s = Stack()symbol_bank = '0123456789ABCDE'#取余數,壓入stackwhile num > 0:item = num % bases.push(item)#除法取整必須使用 //num = num // base#pop并拼湊出字符串result = ''for i in range(s.size()):result += symbol_bank[s.pop()]return resultdef any_to_dec(num, base=2):s = Stack()symbol_bank = '0123456789ABCDE'result = 0i = 0for item in str(num):s.push(item)for i in range(s.size()):item = s.pop()result += symbol_bank.index(item) * base ** ireturn resultdef conversion(num, from_base, to_base):temp = any_to_dec(num, from_base)return dec_to_any(temp, to_base)if __name__ == '__main__':print(dec_to_any(25,2))print(dec_to_any(25,16))print(any_to_dec(11001,2))print(any_to_dec(19,16))print(conversion(11001,2,8))- 注意:
使用reverse來翻轉list比使用stack快10000倍,單純的翻轉操作肯定選reverse,但是stack在入棧以及出棧的時候可以進行一系列的操作,對于某一類問題非常合適!!
from stack import Stack import timeit from timeit import Timerdef reverse_list1(mylist):reversed(mylist)def reverse_list2(mylist):s = Stack()result = []for i in mylist:s.push(i)for i in range(s.size()):mylist[i] = s.pop()if __name__ == '__main__':a = list(range(10000))t1 = Timer('reverse_list1(a)', 'from __main__ import reverse_list1,a')print(t1.timeit(number=100))t2 = Timer('reverse_list2(a)', 'from __main__ import reverse_list2,a')print(t2.timeit(number=100))2.4中綴表達式轉換
2.4.1 轉為后綴表達式
AB+CD -> ABCD+
特征:
- ABCD這些操作數的相對位置不變,直接用一個list逐個存儲即可
- 操作符’+’優先級小于C與D之間的*,故結果中這兩個操作符位置肯定要顛倒,想到用stack的特性
- 括號也要壓入stack,括號內的操作符相當于一個子過程,只有當‘)‘出現,才可以pop從左括號到右括號的所有元素,繼續進行程序
解題思路:
以 "A * B + C * D"為例
#stack綜合運用 #啟發:stack不僅在入棧、出棧過程中可以做文章,比如篩選等操作, #同時,不一定要全部元素入棧后全部再出棧,可以入一部分、出一部分、再入 from stack import Stackdef postpix(exp):opstack = Stack()out_list = []exp = exp.split(' ')for item in exp:if item in operator_bank:if opstack.isEmpty():opstack.push(item)elif operator_bank[opstack.peek()] <= operator_bank[item]:opstack.push(item)else:#當opstack非空,且peek優先值大于當前item,則將opstack'('之后所有操作符pop并添加到out_list,不包括左括號while not opstack.isEmpty():top = opstack.pop()if top == '(':opstack.push('(')breakout_list.append(top)#別忘了先把當前item push進去opstack.push(item)#當遇到')',將opstack中元素pop并添加到out_list,知道遇到‘(’,左括號也要popelif item == ')':while not opstack.isEmpty():top = opstack.pop()if top == '(':breakout_list.append(top)#當字符為操作數else:out_list.append(item)while(not opstack.isEmpty()):top = opstack.pop()out_list.append(top)return ''.join(out_list)if __name__ == '__main__':operator_bank = {'(': 2,'*': 1,'/': 1,'+': 0,'-': 0,}operand_bank = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'# print(postpix("A*B+C*D"))print(postpix("( A + B ) * C - ( D - E ) * ( F + G )"))2.4.2 后綴表達式求值
思路:
以 "7 8 + 3 2 + /"為例
實現:
from stack import Stackdef _do_math(stack, operator):#先pop出的數字為第二個操作數!!!一定要注意順序operand2 = int(stack.pop())operand1 = int(stack.pop())if operator == '+':return operand1 + operand2if operator == '-':return operand1 - operand2if operator == '*':return operand1 * operand2if operator == '/':return operand1 / operand2def evaluate_postfix(exp):"""求后綴算數表達式的值"""operand_stack = Stack()exp_list = exp.split(' ')for item in exp_list:if item in operand_bank:operand_stack.push(item)else:temp = _do_math(operand_stack,item)operand_stack.push(temp)return operand_stack.pop()if __name__ == '__main__':operand_bank = '123456789'print(evaluate_postfix('7 8 + 3 2 + /'))三、參考
http://interactivepython.org/runestone/static/pythonds/BasicDS/toctree.html
總結
- 上一篇: Python内置数据结构及其复杂度
- 下一篇: 队列的实现与应用