資料結構與算法系列6--棧
什麼是棧?
1.後進者先出,先進者後出,這就是典型的“棧”結構。
2.從棧的操作特性來看,是一種“操作受限”的線性表,只允許在端插入和刪除資料。
什麼時候使用?
當某個資料集合只涉及在某端插入和刪除資料,且滿足後進者先出,先進者後出的操作特性時,我們應該首選棧這種資料結構。
棧的陣列實現(自動擴容)
時間複雜度分析:根據均攤複雜度的定義,可以得陣列實現(自動擴容)符合大多數情況是O(1)級別複雜度,個別情況是O(n)級別複雜度,比如自動擴容時,會進行完整資料的拷貝。
空間複雜度分析:在入棧和出棧的過程中,只需要一兩個臨時變數儲存空間,所以O(1)級別。
注意: 我們說空間複雜度的時候,是指除了原本的資料儲存空間外,演算法執行還需要額外的儲存空間。
程式碼實現:
…
棧的連結串列實現
時間複雜度分析:壓棧和彈棧的時間複雜度均為O(1)級別,因為只需更改單個節點的索引即可。
空間複雜度分析:在入棧和出棧的過程中,只需要一兩個臨時變數儲存空間,所以O(1)級別。我們說空間複雜度的時候,是指除了原本的資料儲存空間外,演算法執行還需要額外的儲存空間。
程式碼實現:
…
棧的應用
1.棧在函式呼叫中的應用
作業系統給每個執行緒分配了一塊獨立的記憶體空間,這塊記憶體被組織成“棧”這種結構,用來儲存函式呼叫時的臨時變數。每進入一個函式,就會將其中的臨時變數作為棧幀入棧,當被呼叫函式執行完成,返回之後,將這個函式對應的棧幀出棧。
2.棧在表示式求值中的應用(比如:34+13*9+44-12/3)
利用兩個棧,其中一個用來儲存運算元,另一個用來儲存運算子。我們從左向右遍歷表示式,當遇到數字,我們就直接壓入運算元棧;當遇到運算子,就與運算子棧的棧頂元素進行比較,若比運算子棧頂元素優先順序高,就將當前運算子壓入棧,若比運算子棧頂元素的優先順序低或者相同,從運算子棧中取出棧頂運算子,從運算元棧頂取出2個運算元,然後進行計算,把計算完的結果壓入運算元棧,繼續比較。
3.棧在括號匹配中的應用(比如:{}{()})
用棧儲存為匹配的左括號,從左到右一次掃描字串,當掃描到左括號時,則將其壓入棧中;當掃描到右括號時,從棧頂取出一個左括號,如果能匹配上,則繼續掃描剩下的字串。如果掃描過程中,遇到不能配對的右括號,或者棧中沒有資料,則說明為非法格式。
當所有的括號都掃描完成之後,如果棧為空,則說明字串為合法格式;否則,說明未匹配的左括號為非法格式。
4.如何實現瀏覽器的前進後退功能?
我們使用兩個棧X和Y,我們把首次瀏覽的頁面依次壓如棧X,當點選後退按鈕時,再依次從棧X中出棧,並將出棧的資料一次放入Y棧。當點選前進按鈕時,我們依次從棧Y中取出資料,放入棧X中。當棧X中沒有資料時,說明沒有頁面可以繼續後退瀏覽了。當Y棧沒有資料,那就說明沒有頁面可以點選前進瀏覽了。
思考
我們在講棧的應用時,講到用函式呼叫棧來儲存臨時變數,為什麼函式呼叫要用“棧”來儲存臨時變數呢?用其他資料結構不行嗎?
因為函式呼叫的執行順序符合後進者先出,先進者後出的特點。比如函式中的區域性變數的生命週期的長短是先定義的生命週期長,後定義的生命週期短;還有函式中呼叫函式也是這樣,先開始執行的函式只有等到內部呼叫的其他函式執行完畢,該函式才能執行結束。
正是由於函式呼叫的這些特點,根據資料結構是特定應用場景的抽象的原則,我們優先考慮棧結構。
基於連結串列實現的棧
'''基於連結串列實現的棧'''
class Node():
def __init__(self,data,next=None):
self.data=data
self.next=next
class LinkedStack():
def __init__(self):
#定義棧頂指標
self.top=None
def push(self,data):
node=Node(data)
if self.top:
node.next=self.top
self.top=node
else:
self.top=node
def pop(self):
if self.top:
data=self.top.data
self.top=self.top.next
return data
else:
return False
def __repr__(self):
data=[]
current=self.top
while current:
data.append(current.data)
current=current.next
return "->".join(value for value in data)
if __name__=="__main__":
stack=LinkedStack()
for i in range(6):
stack.push(str(i))
print(stack)
for i in range(7):
print("彈出"+str(stack.pop()))
print(stack)