棧node
棧和隊列是兩個很基礎的數據結構python
通常棧有兩個概念:數據結構
(1)棧區(內存中)app
(2)LIFO(Last In First Out)ide
棧最好的理解方式,能夠理解爲一個桶,往桶裏放盤子,拿出來的時候只能從頂上開始拿。函數
data
單元測試
ADT {測試
method { pushui
pop
spa
上一節實現了先進先出的循環雙端隊列(Deque),支持雙向的push/pop操做,只要實現了Deque就很容易實現棧。
其實用 python 的內置類型 collections.deque 來實現它也很簡單。
用Deque實現stack
先繼承以前寫的 CircualDoubleLinkedList() 類,經過繼承的方式實現Deuqe,以下:
class Deque(CircualDoubleLinkedList): def pop(self): if len(self) == 0: #若是隊列爲空 raise Exception('empty') tailnode = self.tailnode() #定義尾節點 value = tailnode.value #尾節點的值 self.remove(tailnode) #刪除尾節點,O(1) return value #返回刪除節點的value def popleft(self): #另一種從左側刪除的方法 if len(self) == 0: raise Exception("empty") headnode = self.headnode() value = headnode.value self.remove(headnode) return value class Stack(): def __init__(self): self.deque = Deque() #使用內置庫的collections.deque方法更容易實現 def push(self, value): return self.deque.append(value) def pop(self, value): return self.deque.pop(value) def __len__(self): return len(self.deque) def is_empty(self): return len(self) == 0 #單元測試 def test_stack(): s = stack() for i in range(3): s.push(i) assert len(s) == 3 assert s.pop() == 2 assert s.pop() == 1 assert s.pop() == 0 assert s.is_empty() import pytest with pytest.raise(Exception) as excinfo: s.pop() assert "empty" in str(excinfo.value)
棧溢出(Stack over flow)
棧有兩個主要的使用含義:
1.數據結構上所說的後進先出的結構
2.內存結構的棧區
當寫遞歸函數的時候,每一層的遞歸函數都會用棧區來存儲每一層函數它的變量值,若是寫了一個沒有出口的遞歸函數,就會致使棧溢出。
演示棧溢出:
#棧溢出 def infinite_fib(n): return infinite_fib(n-1) + infinite_fib(n-2) #執行這個函數後,會返回異常 if __name__ == "__main__": infinite_fib(10)
出現棧溢出是由於內存分配給棧區的大小是固定的,當寫了一個無窮遞歸的函數,棧空間很快就會被用完,就會拋出builtins.RecursionError: maximum recursion depth exceeded的棧異常。
因此寫遞歸必定要注意必需要有遞歸出口,這也是寫遞歸函數的坑。
最後,建議看看內置庫collections.deque的實現,有輪子直接拿來用,就簡單多了。