棧(stack)又名堆棧,它是一種運算受限的線性表。其限制是僅允許在表的一端進行插入和刪除運算。
棧允許進行插入和刪除操作的一端稱為棧頂(top),另一端為棧底(bottom);棧底固定,而棧頂浮動;棧中元素個數為零時稱為空棧。插入一般稱為進棧(PUSH),刪除則稱為退棧(POP)。
由於堆疊數據結構只允許在一端進行操作,因而按照后進先出(LIFO, Last In First Out)的原理運作。棧也稱為后進先出表。
棧的演示
Visualgo這個網站,我們可以看到整個數據結構的變化過程。可以通過左下角的按鈕調慢演示過程。可能也自己動手 code 實現了過程,那么再在網站上演示一下元素的各種操作過程,會帶來一些更直觀的印象。
復雜度分析
棧屬於常見的一種線性結構,對於進棧和退棧而言,時間復雜度都為 O(1)
在接下來的內容里,我們將逐步介紹棧的具體功能是如何實現的。
1. 創建一個 Stack 的類
對棧進行初始化參數設計
具體實現代碼如下:
class Stack(object): def __init__(self, limit=10): self.stack = [] #存放元素 self.limit = limit #棧容量極限
2. push 進棧
壓入 push :將新元素放在棧頂
當新元素入棧時,棧頂上移,新元素放在棧頂。
具體實現代碼如下:
def push(self, data): if len(self.stack) >= self.limit: #判斷棧是否溢出 print('StackOverflowError') pass self.stack.append(data)
3. pop 退棧
彈出 pop :從棧頂移出一個數據
- 棧頂元素拷貝出來
- 棧頂下移
- 拷貝出來的棧頂作為函數返回值
具體實現代碼如下:
def pop(self): if self.stack: return self.stack.pop() else: raise IndexError('pop from an empty stack') #空棧不能被彈出
4. 添加其他函數
peek : 查看堆棧的最上面的元素
is_empty : 判斷棧是否為空
size : 返回棧的大小
具體實現代碼如下:
def peek(self): if self.stack: return self.stack[-1] def is_empty(self): return not bool(self.stack) def size(self): return len(self.stack)
完整代碼如下:
class Stack(object): def __init__(self, limit=10): self.stack = [] #存放元素 self.limit = limit #棧容量極限 def push(self, data): #判斷棧是否溢出 if len(self.stack) >= self.limit: print('StackOverflowError') pass self.stack.append(data) def pop(self): if self.stack: return self.stack.pop() else: raise IndexError('pop from an empty stack') #空棧不能被彈出 def peek(self): #查看堆棧的最上面的元素 if self.stack: return self.stack[-1] def is_empty(self): #判斷棧是否為空 return not bool(self.stack) def size(self): #返回棧的大小 return len(self.stack)
Stack(棧)在教科書中有一些非常經典的應用,例如:
- 一些其他有趣的應用程序但沒有用於教學目的
- 括號匹配
- 后綴計算器
作業:檢查括號是否完全匹配
使用一個堆棧檢查括號字符串是否平衡
有效括號字符串需滿足:
- 左括號必須用相同類型的右括號閉合。
- 左括號必須以正確的順序閉合。
- 注意空字符串可被認為是有效字符串。
舉例:
((())): True
((()): False
(())): False
目標:
- 使用一個堆棧作為數據結構
- 來檢查括號字符串是否完全匹配
class Stack(object): def __init__(self, limit=10): self.stack = [] #存放元素 self.limit = limit #棧容量極限 def push(self, data): #判斷棧是否溢出 if len(self.stack) >= self.limit: print('StackOverflowError') pass self.stack.append(data) def pop(self): if self.stack: return self.stack.pop() else: raise IndexError('pop from an empty stack') #空棧不能被彈出 def peek(self): #查看堆棧的最上面的元素 if self.stack: return self.stack[-1] def is_empty(self): #判斷棧是否為空 return not bool(self.stack) def size(self): #返回棧的大小 return len(self.stack) def balanced_parentheses(parentheses): stack = Stack(len(parentheses)) for parenthesis in parentheses: if parenthesis == '(': stack.push(parenthesis) elif parenthesis == ')': if stack.is_empty(): return False stack.pop() return stack.is_empty() if __name__ == '__main__': examples = ['((()))', '((())', '(()))'] print('Balanced parentheses demonstration:\n') for example in examples: print(example + ': ' + str(balanced_parentheses(example)))