9.棧(stack)

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的實現,有輪子直接拿來用,就簡單多了。

相關文章
相關標籤/搜索