栈 / Stack
目录
- 链表栈
- 数组栈
栈是一种基本的线性数据结构(先入后出FILO),在 C 语言中有链表和数组两种实现方式,下面用 Python 对这两种栈进行实现。
1 链表栈
链表栈是以单链表为基础实现的栈数据结构,主要有以下几个关键点:
- 栈顶元素:栈顶元素即为链表的头结点
- 压栈:向链表的头结点插进入栈元素,无表头链表则替换插入元素为头结点
- 弹栈:弹出链表头结点,并将链表头结点替换为下一个元素
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. 单链表