Python與數據結構[1] -> 棧/Stack[0] -> 鏈表棧與數組棧的 Python 實現


/ Stack


目錄

  1. 鏈表棧
  2. 數組棧

 

棧是一種基本的線性數據結構(先入后出FILO),在 C 語言中有鏈表和數組兩種實現方式,下面用 Python 對這兩種棧進行實現。

1 鏈表棧

鏈表棧是以單鏈表為基礎實現的棧數據結構,主要有以下幾個關鍵點:

  1. 棧頂元素:棧頂元素即為鏈表的頭結點
  2. 壓棧:向鏈表的頭結點插進入棧元素,無表頭鏈表則替換插入元素為頭結點
  3. 彈棧:彈出鏈表頭結點,並將鏈表頭結點替換為下一個元素
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())
View Code

分段解釋
以鏈表為基礎的棧實現,首先需要定義鏈表結點,以及棧滿壓棧和棧空彈棧的異常類,

 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!

  

2 數組棧

數組棧是棧的另一種實現方式,在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())
View Code

分段解釋

首先從鏈表棧中導入兩個異常類和測試函數,

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. 單鏈表


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM