堆棧就像一個數組,但功能有限。 你只能在堆棧的頂部添加(push方法,或稱為進棧、入棧、壓棧)一個新的元素,彈出(pop方法,或稱為退棧,出棧)從頂部的元素并刪除,或者只查看(peek方法)頂部的元素,而不刪除。
你為什么要這樣做? 好吧,在許多算法中,您希望在某個時間點將對象添加到臨時列表,然后再次將其從此列表中刪除。 通常,添加和刪除這些對象的順序很重要。
堆棧的順序是先入后出。 你最后一次添加的元素,下一次彈出操作時就會被彈出來。(一個非常相似的數據結構,隊列,是先入先出。)
例如,讓我們在堆棧上添加一個數字:
stack.push(10)
堆棧現在是[10]。 添加下一個數字:
stack.push(3)
堆棧現在是[10,3]。 再添加一個數字:
stack.push(57)
堆棧現在是[10,3,57]。 讓我們彈出堆棧頂端的數字:
stack.pop()
這次返回57,因為這是彈出的是最近添加的數字。 堆棧又變成了[10,3]。
stack.pop()
這次返回3,依此類推。 如果堆棧是空的,出堆棧方法返回nil或者在一些情況下,給它打印一個錯誤消息(“堆棧下溢”)。
堆棧很容易在Swift中創建。 它只是一個數組的包裝,只是讓你push,pop和peek:
public struct Stack<T> {
fileprivate var array = [T]()
public var isEmpty: Bool {
return array.isEmpty
}
public var count: Int {
return array.count
}
public mutating func push(_ element: T) {
array.append(element)
}
public mutating func pop() -> T? {
return array.popLast()
}
public func peek() -> T? {
return array.last
}
}
注意,push將新元素放在數組的尾部,而不是頭部。 在數組的頭部插入是費時的O(n)操作,因為它要求所有的數組元素在內存中移動。 從尾部添加耗時是O(1); 每次消耗的時間是一樣的,而不管元素的多少。
堆棧的趣事:每次調用函數或方法時,CPU都會將返回地址放在堆棧上。 當函數結束時,CPU使用該返回地址,跳回到調用者。 這就是為什么如果你調用太多的函數 - 例如在一個遞歸函數,永遠不會結束 - 你會得到一個所謂的“堆棧溢出”(即著名的網站 stack overflow),因為CPU堆棧已經耗盡了空間。
作者: Matthijs Hollemans -- Swift算法俱樂部
英文鏈接:
https://github.com/raywenderlich/swift-algorithm-club/tree/master/Stack