資料結構與演算法-棧、佇列
阿新 • • 發佈:2020-08-05
棧
- 特性:先進後出的資料結構
- 棧頂,棧尾
- 入棧:向棧頂新增元素(從棧頂向棧底新增元素)
- 出棧:從棧頂獲取元素(從棧頂取出元素)
- 應用:每個 web 瀏覽器都有一個返回按鈕。當你瀏覽網頁時,這些網頁被放置在一個棧中(實際是網頁的網址)。你現在檢視的網頁在頂部,你第一個檢視的網頁在底部。如果按‘返回’按鈕,將按相反的順序瀏覽剛才的頁面。
- Stack() 建立一個空的新棧。 它不需要引數,並返回一個空棧。
- push(item)將一個新項新增到棧的頂部。它需要 item 做引數並不返回任何內容。
- pop() 從棧中刪除頂部項。它不需要引數並返回 item 。棧被修改。
- peek() 從棧返回頂部項,但不會刪除它。不需要引數。 不修改棧。
- isEmpty() 測試棧是否為空。不需要引數,並返回布林值。
- size() 返回棧中的 item 數量。不需要引數,並返回一個整數。
class Stack(): def __init__(self): self.items = [] def push(self, item): self.items.append(item) def pop(self): return self.items.pop()def isEmpty(self): return self.items == [] def size(self): return len(self.items) # 返回棧頂元素的下標 def peek(self): return len(self.items) - 1
佇列
- 佇列:先進先出
- 隊頭:直接從隊頭出佇列(取出元素)
- 隊尾:從隊尾新增元素
- 應用場景:
- 我們的計算機實驗室有 30 臺計算機與一臺印表機聯網。當學生想要列印時,他們的列印任務與正在等待的所有其他列印任務“一致”。第一個進入的任務是先完成。如果你是最後一個,你必須等待你前面的所有其他任務列印
- Queue() 建立一個空的新佇列。 它不需要引數,並返回一個空佇列。
- enqueue(item) 將新項新增到隊尾。 它需要 item 作為引數,並不返回任何內容。
- dequeue() 從隊首移除項。它不需要引數並返回 item。 佇列被修改。
- isEmpty() 檢視佇列是否為空。它不需要引數,並返回布林值。
- size() 返回佇列中的項數。它不需要引數,並返回一個整數。
class Queue(): def __init__(self): self.items = [] def enqueue(self,item): self.items.insert(0,item) def dequeue(self): return self.items.pop() def size(self): return len(self.items) def isEmpty(self): return self.items == []
雙端佇列
- 同同列相比,有兩個頭部和尾部。可以在雙端進行資料的插入和刪除,提供了單資料結構中棧和佇列的特性
- Deque() 建立一個空的新 deque。它不需要引數,並返回空的 deque。
- addFront(item) 將一個新項新增到 deque 的首部。它需要 item 引數 並不返回任何內容。
- addRear(item) 將一個新項新增到 deque 的尾部。它需要 item 引數並不返回任何內容。
- removeFront() 從 deque 中刪除首項。它不需要引數並返回 item。deque 被修改。
- removeRear() 從 deque 中刪除尾項。它不需要引數並返回 item。deque 被修改。
- isEmpty() 測試 deque 是否為空。它不需要引數,並返回布林值。
- size() 返回 deque 中的項數。它不需要引數,並返回一個整數。
class Dequeue(): def __init__(self): self.items = [] def addFont(self,item): self.items.append(item) def addRear(self,item): self.items.insert(0,item) def removeFont(self): return self.items.pop() def removeRear(self): return self.items.pop(0) def isEmpty(self): return self.items == [] def size(self): return len(self.items)
應用
案例一:燙手的山芋(佇列應用)
- 燙手山芋遊戲介紹:6個孩子圍城一個圈,排列順序孩子們自己指定。第一個孩子手裡有一個燙手的山芋,需要在計時器計時1秒後將山芋傳遞給下一個孩子,依次類推。規則是,在計時器每計時7秒時,手裡有山芋的孩子退出遊戲。該遊戲直到剩下一個孩子時結束,最後剩下的孩子獲勝。請使用佇列實現該遊戲策略,排在第幾個位置最終會獲勝。
- 分析:
- 1.每輪遊戲的時間為7s
- 2.山芋在一輪遊戲中會被傳遞幾次:6次
- 3.一輪遊戲結束後,需要淘汰一個孩子,孩子需要從佇列中剔除
- 佇列只能從隊頭位置取出元素
- 保證手裡有山芋的孩子永遠在隊頭的位置
# 將6個孩子加入到佇列中 kids = ['A','B','C','D','E','F'] q = Queue() for kid in kids: q.enqueue(kid) while q.size() > 1: # 結束遊戲的條件 # 開始一輪遊戲 for i in range(6):# 山芋傳遞的次數 kid = q.dequeue() # 將隊頭的孩子取出 q.enqueue(kid) # 將隊頭的孩子取出,新增到隊尾 # 一輪遊戲結束需要將隊頭元素出佇列(將手中有山芋的孩子淘汰遊戲) q.dequeue() print(q.dequeue()) # 檢視最後剩下的孩子 E
案例二:兩個佇列實現棧(用倆個先進先出實現先進後出)
q1 = Queue() q2 = Queue() items = [1,2,3,4,5,6] for item in items: q1.enqueue(item) while q1.size() >= 1: # 將q1中的前n-1個元素取出加入到q2中 while q1.size() > 1: item = q1.dequeue() # 將q1留1個,其他元素取出放入q2 q2.enqueue(item) print(q1.dequeue()) # 取出q1剩餘的最後一個元素 q1,q2 = q2,q1 # 將q1,q2互換 6 5 4 3 2 1
案例三:兩個棧實現佇列(用倆個先進後出實現先進先出)
s1 = Stack() s2 = Stack() items = [1,2,3,4,5,6] for item in items: s1.push(item) while s1.size() >= 1: while s1.size() > 1: item = s1.pop() s2.push(item) # s2:6,5,4,3,2 s1:1 print(s1.pop()) # s2:6,5,4,3,2 s1:空 while s2.size() >= 1: item = s2.pop() # s2:空 s1:2,3,4,5,6 s1.push(item) 1 2 3 4 5 6
案例四:迴文檢查(雙端佇列)
雙端佇列應用案例:迴文檢查
- 迴文是一個字串,讀取首尾相同的字元,例如,radar toot madam。
def isHuiWen(aString): de = Dequeue() for ch in aString: de.addFont(ch) ex = True while de.size()>1: # 取出最前和最後元素對比 if de.removeFont() != de.removeRear(): ex = False return ex print(isHuiWen('abaa'))