棧 / Stack
目錄
棧是一種基本的線性數據結構(先入后出FILO),在 C 語言中有鏈表和數組兩種實現方式,下面用 Python 對這兩種棧進行實現。
鏈表棧是以單鏈表為基礎實現的棧數據結構,主要有以下幾個關鍵點:
- 棧頂元素:棧頂元素即為鏈表的頭結點
- 壓棧:向鏈表的頭結點插進入棧元素,無表頭鏈表則替換插入元素為頭結點
- 彈棧:彈出鏈表頭結點,並將鏈表頭結點替換為下一個元素
Stack based on linked list:
| item3 |
| | |
| V |
| item2 |
| | |
| V |
| item1 |
-------
完整代碼

1 class StackEmptyException(Exception): pass 2 3 4 class StackFullException(Exception): pass 5 6 7 class Node: 8 def __init__(self, val=None, nxt=None): 9 self.value = val 10 self.next = nxt 11 12 def __str__(self): 13 return str(self.value) 14 15 16 class Stack: 17 """ 18 Stack based on linked list: 19 | item3 | 20 | | | 21 | V | 22 | item2 | 23 | | | 24 | V | 25 | item1 | 26 ------- 27 """ 28 def __init__(self, max=0): 29 self._top = None 30 self._max = 0 31 self.max = max 32 33 @property 34 def max(self): 35 return self._max 36 37 @max.setter 38 def max(self, m): 39 m = int(m) 40 if m < self.length: 41 raise Exception('Resize stack failed, please pop some elements first.') 42 self._max = m 43 if self._max < 0: 44 self._max = 0 45 46 def init(self, iterable=()): 47 if not iterable: 48 return 49 self._top = Node(iterable[0]) 50 for i in iterable[1:]: 51 node = self._top 52 self._top = Node(i) 53 self._top.next = node 54 55 def show(self): 56 def _traversal(self): 57 node = self._top 58 while node and node.next: 59 yield node 60 node = node.next 61 yield node 62 print('\n'.join(map(lambda x: '|{:^7}|'.format(str(x)), _traversal(self)))+'\n '+7*'-') 63 64 @property 65 def length(self): 66 if self._top is None: 67 return 0 68 node = self._top 69 i = 1 70 while node.next: 71 node = node.next 72 i += 1 73 return i 74 75 @property 76 def is_empty(self): 77 return self._top is None 78 79 @property 80 def is_full(self): 81 return bool(self._max and self.length == self._max) 82 83 def push(self, item): 84 if self.is_full: 85 raise StackFullException('Error: trying to push element into a full stack!') 86 if not self._top: 87 self._top = Node(item) 88 return 89 node = self._top 90 self._top = Node(item) 91 self._top.next = node 92 93 def pop(self): 94 if self.is_empty: 95 raise StackEmptyException('Error: trying to pop element from an empty stack!') 96 node = self._top 97 self._top = self._top.next 98 return node.value 99 100 def top(self): 101 return self._top.value if self._top else self._top 102 103 def clear(self): 104 while self._top: 105 self.pop() 106 107 108 def test(stack): 109 print('\nShow stack:') 110 stack.show() 111 112 print('\nInit linked list:') 113 stack.init([1, 2, 3, 4, 5]) 114 stack.show() 115 116 print('\nPush element to stack:') 117 stack.push(6) 118 stack.push(7) 119 stack.push('like') 120 stack.show() 121 122 print('\nCheck top element:') 123 print(stack.top()) 124 125 print('\nPop element from stack:') 126 e = stack.pop() 127 print('Element %s popped,' % e) 128 stack.show() 129 130 print('\nSet stack max size:') 131 try: 132 stack.max = 1 133 except Exception as e: 134 print(e) 135 136 print('\nSet stack max size:') 137 stack.max = 7 138 print(stack.max) 139 140 print('\nPush full stack:') 141 try: 142 stack.push(7) 143 except StackFullException as e: 144 print(e) 145 146 print('\nClear stack:') 147 stack.clear() 148 stack.show() 149 150 print('\nStack is empty:') 151 print(stack.is_empty) 152 153 print('\nPop empty stack:') 154 try: 155 stack.pop() 156 except StackEmptyException as e: 157 print(e) 158 159 if __name__ == '__main__': 160 test(Stack())
分段解釋
以鏈表為基礎的棧實現,首先需要定義鏈表結點,以及棧滿壓棧和棧空彈棧的異常類,
1 class StackEmptyException(Exception): pass 2 3 4 class StackFullException(Exception): pass 5 6 7 class Node: 8 def __init__(self, val=None, nxt=None): 9 self.value = val 10 self.next = nxt 11 12 def __str__(self): 13 return str(self.value)
定義棧類,主要包括兩個屬性,即棧頂元素和棧大小,
1 class Stack: 2 """ 3 Stack based on linked list: 4 | item3 | 5 | | | 6 | V | 7 | item2 | 8 | | | 9 | V | 10 | item1 | 11 ------- 12 """ 13 def __init__(self, max=0): 14 self._top = None 15 self._max = 0 16 self.max = max
定義棧最大容量max為屬性方法,當設置棧的最大容量值時,若傳入的大小小於當前棧大小則提示異常,若傳入0或負數大小,則設為無限容量的棧。
1 @property 2 def max(self): 3 return self._max 4 5 @max.setter 6 def max(self, m): 7 m = int(m) 8 if m < self.length: 9 raise Exception('Resize stack failed, please pop some elements first.') 10 self._max = m 11 if self._max < 0: 12 self._max = 0
定義棧的init方法,用於初始化一個可迭代對象為棧結構,接受一個可迭代對象,當空棧時以第一個元素為棧頂,隨后依次壓棧,最后入棧的元素為棧頂元素。
1 def init(self, iterable=()): 2 if not iterable: 3 return 4 self._top = Node(iterable[0]) 5 for i in iterable[1:]: 6 node = self._top 7 self._top = Node(i) 8 self._top.next = node
定義棧的show方法,用於顯示棧,首先遍歷棧元素,然后依照格式化輸出,當空棧時則棧頂/底元素為None。
1 def show(self): 2 def _traversal(self): 3 node = self._top 4 while node and node.next: 5 yield node 6 node = node.next 7 yield node 8 print('\n'.join(map(lambda x: '|{:^7}|'.format(str(x)), _traversal(self)))+'\n '+7*'-')
定義棧的length屬性方法,用於返回當前棧內元素數量,通過鏈表遍歷計數實現(類似獲取鏈表長度)。
1 @property 2 def length(self): 3 if self._top is None: 4 return 0 5 node = self._top 6 i = 1 7 while node.next: 8 node = node.next 9 i += 1 10 return i
定義棧的is_empty屬性方法,用於判斷棧是否為空棧。
1 @property 2 def is_empty(self): 3 return self._top is None
定義棧的is_full屬性方法,用於判斷棧容量是否已滿。
1 @property 2 def is_full(self): 3 return bool(self._max and self.length == self._max)
定義棧的push方法,用於實現壓棧過程,即向棧鏈前端插入入棧元素,棧滿壓棧則提示異常。
1 def push(self, item): 2 if self.is_full: 3 raise StackFullException('Error: trying to push element into a full stack!') 4 if not self._top: 5 self._top = Node(item) 6 return 7 node = self._top 8 self._top = Node(item) 9 self._top.next = node
定義棧的pop方法,用於實現彈棧過程,彈出棧頂元素並替換棧頂元素為下一個元素,棧空彈棧則提示異常。
1 def pop(self): 2 if self.is_empty: 3 raise StackEmptyException('Error: trying to pop element from an empty stack!') 4 node = self._top 5 self._top = self._top.next 6 return node.value
定義棧的top方法,用於獲取棧頂元素,當棧頂元素為None時,返回None。
1 def top(self): 2 return self._top.value if self._top else self._top
定義棧的clear方法,用於清空棧,即依次彈棧至空棧。
1 def clear(self): 2 while self._top: 3 self.pop()
最后定義一個測試函數,用於對棧類進行操作測試。
首先實例化一個棧,並將一個列表元素依次壓入棧中,最后顯示棧元素
1 def test(stack): 2 print('\nShow stack:') 3 stack.show() 4 5 print('\nInit linked list:') 6 stack.init([1, 2, 3, 4, 5]) 7 stack.show()
得到結果
1 Show stack: 2 | None | 3 ------- 4 5 Init linked list: 6 | 5 | 7 | 4 | 8 | 3 | 9 | 2 | 10 | 1 | 11 -------
執行壓棧操作,將元素壓入棧中,
1 print('\nPush element to stack:') 2 stack.push(6) 3 stack.push(7) 4 stack.push('like') 5 stack.show()
得到結果
Push element to stack:
| like |
| 7 |
| 6 |
| 5 |
| 4 |
| 3 |
| 2 |
| 1 |
-------
檢測棧頂元素並彈出棧頂元素
1 print('\nCheck top element:') 2 print(stack.top()) 3 4 print('\nPop element from stack:') 5 e = stack.pop() 6 print('Element %s popped,' % e) 7 stack.show()
得到結果
Check top element: like Pop element from stack: Element like popped, | 7 | | 6 | | 5 | | 4 | | 3 | | 2 | | 1 | -------
嘗試修改棧的最大容量,當修改容量小於當前棧內元素數量時,將會觸發異常
1 print('\nSet stack max size:') 2 try: 3 stack.max = 1 4 except Exception as e: 5 print(e) 6 7 print('\nSet stack max size:') 8 stack.max = 7 9 print(stack.max)
得到結果
Set stack max size:
Resize stack failed, please pop some elements first.
Set stack max size:
7
嘗試對一個滿元素棧進行壓棧操作,將引發異常
1 print('\nPush full stack:') 2 try: 3 stack.push(7) 4 except StackFullException as e: 5 print(e)
得到結果
Push full stack:
Error: trying to push element into a full stack!
隨后清空棧,並檢查棧是否為空,最后嘗試對空棧進行彈棧操作,同樣會引發一個異常
1 print('\nClear stack:') 2 stack.clear() 3 stack.show() 4 5 print('\nStack is empty:') 6 print(stack.is_empty) 7 8 print('\nPop empty stack:') 9 try: 10 stack.pop() 11 except StackEmptyException as e: 12 print(e)
得到結果
Clear stack: | None | ------- Stack is empty: True Pop empty stack: Error: trying to pop element from an empty stack!
數組棧是棧的另一種實現方式,在C語言中以數組的形式實現,而在Python中,則可以使用與數組類似的列表進行實現。
Stack based on array/list:
| 4 |
| 3 |
| 2 |
| 1 |
-------
數組棧中需要實現的方法接口與鏈表棧相同。只是在數據存儲時由鏈表變成了數組/列表。由於Python的列表本身即是一種很方便的線性結構,因此數組棧的實現十分簡單。
完整代碼

1 from linked_list_stack import StackEmptyException, StackFullException, test 2 3 4 class Stack: 5 """ 6 Stack based on array/list: 7 | 4 | 8 | 3 | 9 | 2 | 10 | 1 | 11 ------- 12 """ 13 def __init__(self, max=0): 14 self._array = [] 15 self._max = 0 16 self.max = max 17 18 @property 19 def max(self): 20 return self._max 21 22 @max.setter 23 def max(self, m): 24 m = int(m) 25 if m < self.length: 26 raise Exception('Resize stack failed, please pop some elements first.') 27 self._max = m 28 if self._max < 0: 29 self._max = 0 30 31 def init(self, iterable=()): 32 if not iterable: 33 return 34 for i in iterable: 35 self._array.append(i) 36 37 def show(self): 38 def _traversal(self): 39 if not self._array: 40 return [None] 41 return self._array[::-1] 42 print('\n'.join(map(lambda x: '|{:^7}|'.format(str(x)), _traversal(self)))+'\n '+7*'-') 43 44 @property 45 def length(self): 46 return len(self._array) 47 48 @property 49 def is_empty(self): 50 return self._array == [] 51 52 @property 53 def is_full(self): 54 return bool(self._max and self.length == self._max) 55 56 def push(self, item): 57 if self.is_full: 58 raise StackFullException('Error: trying to push element into a full stack!') 59 self._array.append(item) 60 61 def pop(self): 62 if self.is_empty: 63 raise StackEmptyException('Error: trying to pop element from an empty stack!') 64 return self._array.pop() 65 66 def top(self): 67 return self._array[-1] 68 69 def clear(self): 70 # self._array = [] 71 while self._array: 72 self.pop() 73 74 75 if __name__ == '__main__': 76 test(Stack())
分段解釋
首先從鏈表棧中導入兩個異常類和測試函數,
1 from linked_list_stack import StackEmptyException, StackFullException, test
然后定義棧類,與鏈表棧不同的地方在於,存儲數據的方式換成了列表
1 class Stack: 2 """ 3 Stack based on array/list: 4 | 4 | 5 | 3 | 6 | 2 | 7 | 1 | 8 ------- 9 """ 10 def __init__(self, max=0): 11 self._array = [] 12 self._max = 0 13 self.max = max
與前面的鏈表棧一樣,定義棧的容量。
1 @property 2 def max(self): 3 return self._max 4 5 @max.setter 6 def max(self, m): 7 m = int(m) 8 if m < self.length: 9 raise Exception('Resize stack failed, please pop some elements first.') 10 self._max = m 11 if self._max < 0: 12 self._max = 0
定義棧的init方法,添加入棧元素時只需要在列表末尾加入元素即可,
1 def init(self, iterable=()): 2 if not iterable: 3 return 4 for i in iterable: 5 self._array.append(i)
下面的幾個方法與鏈表棧類似,只是操作時換成了對數組列表的檢測,
1 def show(self): 2 def _traversal(self): 3 if not self._array: 4 return [None] 5 return self._array[::-1] 6 print('\n'.join(map(lambda x: '|{:^7}|'.format(str(x)), _traversal(self)))+'\n '+7*'-') 7 8 @property 9 def length(self): 10 return len(self._array) 11 12 @property 13 def is_empty(self): 14 return self._array == [] 15 16 @property 17 def is_full(self): 18 return bool(self._max and self.length == self._max)
定義棧的push方法,實現壓棧操作,壓棧只需要對列表進行append即可,
1 def push(self, item): 2 if self.is_full: 3 raise StackFullException('Error: trying to push element into a full stack!') 4 self._array.append(item)
定義棧的pop方法,實現彈棧操作,彈棧只需要對列表進行pop即可,
1 def pop(self): 2 if self.is_empty: 3 raise StackEmptyException('Error: trying to pop element from an empty stack!') 4 return self._array.pop()
定義棧的top方法,實現棧頂元素獲取,返回列表最后一位元素即可,
1 def top(self): 2 return self._array[-1]
定義棧的clear方法,實現棧的清空操作,可以直接清空數組列表或依次將棧內元素彈出棧,
1 def clear(self): 2 # self._array = [] 3 while self._array: 4 self.pop()
最后,利用測試函數對數組棧進行測試
1 if __name__ == '__main__': 2 test(Stack())
得到結果與鏈表棧相同
Show stack: | None | ------- Init linked list: | 5 | | 4 | | 3 | | 2 | | 1 | ------- Push element to stack: | like | | 7 | | 6 | | 5 | | 4 | | 3 | | 2 | | 1 | ------- Check top element: like Pop element from stack: Element like popped, | 7 | | 6 | | 5 | | 4 | | 3 | | 2 | | 1 | ------- Set stack max size: Resize stack failed, please pop some elements first. Set stack max size: 7 Push full stack: Error: trying to push element into a full stack! Clear stack: | None | ------- Stack is empty: True Pop empty stack: Error: trying to pop element from an empty stack!
相關閱讀
1. 單鏈表