ADT Stack:
数据对象: D = a i ∣ a i ∈ D a t a T y p e , i = 1 , 2 , . . . , n , n ≥ 0 D={a_i|a_i∈DataType, i=1,2,…,n,n\geq0} D=ai∣ai∈DataType,i=1,2,…,n,n≥0
数据关系: R = < a i , a i + 1 > ∣ a i , a i + 1 ∈ D , i = 1 , 2 , . . . , n − 1 R={<a_{i},a_{i+1}>|a_i,a_{i+1}∈D,i=1,2,…,n-1} R=<ai,ai+1>∣ai,ai+1∈D,i=1,2,…,n−1
a 1 a_1 a1为栈底元素, a n a_n an为栈顶元素
基本操作:
1. __itit__(): 初始化栈
创建一个空栈
2. size(): 求取并返回栈中所含元素的个数 n
若栈为空,则返回整数0
3. isempty(): 判断是否为空栈
判断栈中是否存储元素
4. push(data): 入栈
将元素 data 插入栈顶
5. pop(): 出栈
删除并返回栈顶元素
4. peek(): 取栈顶元素
返回栈顶元素值,但并不删除元素
1.3 栈的应用场景
栈具有广泛的应用场景,例如:
-
符号的匹配,具体描述参考第3.3小节;
-
函数调用,每个未结束调用的函数都会在函数栈中拥有一块数据区,保存了函数的重要信息,包括函数的局部变量、参数等;
-
后缀表达式求值,计算后缀表达式只需一个用于存放数值的栈,遍历表达式遇到数值则入栈,遇到运算符则出栈两个数值进行计算,并将计算结果入栈,最后栈中保留的唯一值即为表达式结果;
-
网页浏览中的返回按钮,当我们在网页间进行跳转时,这些网址都被存放在一个栈中;
-
编辑器中的撤销序列,与网页浏览中的返回按钮类似,栈保存每步的编辑操作。
除了以上应用外,我们在之后的学习中还将看到栈用作许多算法的辅助数据结构。
和线性表一样,栈同样有两种存储表示方式。
2.1 顺序栈的实现
顺序栈是栈的顺序存储结构,其利用一组地址连续的存储单元从栈底到栈顶依次存放。同时使用指针 top
来指示栈顶元素在顺序栈中的索引,同样顺序栈可以是固定长度和动态长度,当栈满时,定长顺序栈会抛出栈满异常,动态顺序栈则会动态申请空闲空间。
2.1.1 栈的初始化
顺序栈的初始化需要三部分信息:stack
列表用于存储数据元素,max_size
用于存储 stack
列表的最大长度,以及 top
用于记录栈顶元素的索引:
class Stack:
def init(self, max_size=10):
self.max_size = max_size
self.stack = self.max_size * [None]
self.top = -1
2.1.2 求栈长
由于 top
表示栈顶元素的索引,我们可以据此方便的计算顺序栈中的数据元素数量,即栈长:
def size(self):
return self.top + 1
2.1.3 判栈空
根据栈的长度可以很容易的判断栈是否为空栈:
def isempty(self):
if self.size() == 0:
return True
else:
return False
2.1.4 判栈满
由于需要提前申请栈空间,因此我们需要能够判断栈是否还有空闲空间:
def isfully(self):
if self.size() == self.max_size:
return True
else:
return False
2.1.5 入栈
入栈时,需要首先判断栈中是否还有空闲空间,然后根据栈为定长顺序栈或动态顺序栈,入栈操作稍有不同:
[定长顺序栈的入栈操作] 如果栈满,则引发异常:
def push(self, data):
if self.isfully():
raise IndexError(‘Stack Overflow!’)
else:
self.top += 1
self.stack[self.top_1] = data
[动态顺序栈的入栈操作] 如果栈满,则首先申请新空间:
def resize(self):
new_size = 2 * self.max_size
new_stack = [None] * new_size
for i in range(self.num_items):
new_stack[i] = self.items[i]
self.stack = new_stack
self.max_size = new_size
def push(self, data):
if self.isfully():
self.resize()
else:
self.top += 1
self.stack[self.top_1] = data
入栈的时间复杂度为 O ( 1 ) O(1) O(1)。这里需要注意的是,虽然当动态顺序栈满时,原栈中的元素需要首先复制到新栈中,然后添加新元素,但根据《顺序表及其操作实现》中顺序表追加操作的介绍,由于 n
次入栈操作的总时间 T ( n ) T(n) T(n) 与 O ( n ) O(n) O(n) 成正比,因此入栈的摊销时间复杂度仍可以认为是 O ( 1 ) O(1) O(1)。
2.1.6 出栈
若栈不空,则删除并返回栈顶元素:
def pop(self):
if self.isempty():
raise IndexError(‘Stack Underflow!’)
else:
result = self.stack[self.top]
self.top -= 1
return result
2.1.7 求栈顶元素
若栈不空,则只需返回栈顶元素:
def peek(self):
if self.isempty():
raise IndexError(‘Stack Underflow!’)
else:
return self.stack[self.top]
2.2 链栈的实现
栈的另一种存储表示方式是使用链式存储结构,因此也常称为链栈,其中 push
操作是通过在链表头部插入元素来实现的,pop
操作是通过从头部删除节点来实现的。
2.2.1 栈结点
栈的结点实现与链表并无差别:
class Node:
def init(self, data):
self.data = data
self.next = None
def str(self):
return str(self.data)
2.2.2 栈的初始化
栈的初始化函数中,使栈顶指针指向 None
,并初始化栈长:
class Stack:
def init(self):
self.top = None
栈中元素数
self.length = 0
2.2.3 求栈长
返回 length
的值用于求取栈的长度,如果没有 length
属性,则需要遍历整个链表才能得到栈长:
def size(self):
return self.length
2.2.4 判栈空
根据栈的长度可以很容易的判断栈是否为空栈:
def isempty(self):
if self.length == 0:
return True
else:
return False
2.2.5 入栈
入栈时,在栈顶插入新元素即可:
def push(self, data):
p = Node(data)
p.next = self.top
self.top = p
self.length += 1
由于插入元素是在链表头部进行的,因此入栈的时间复杂度为 O ( 1 ) O(1) O(1),在这种情况下链尾作为栈底 。
2.2.5 出栈
若栈不空,则删除并返回栈顶元素:
def pop(self):
if self.isempty():
raise IndexError(“Stack Underflow!”)
ele = self.top.data
self.top = self.top.next
self.length -= 1
return ele
由于删除元素仅需修改头指针指向其 next
域,因此出栈的时间复杂度同样为 O ( 1 ) O(1) O(1)。
2.2.6 求栈顶元素
若栈不空,返回栈顶元素即可,但栈顶元素并不会被删除:
def peek(self):
if self.isempty():
raise IndexError(“Stack Underflow!”)
return self.top.data
2.3 栈的不同实现对比
本节我们将对比栈的不同实现之间的异同:
-
顺序栈
-
操作的时间复杂度均为 O ( 1 ) O(1) O(1),列表的尾部作为栈顶
-
栈满时需要进行动态的扩展,复制原栈元素到新栈中
-
链栈
-
操作的时间复杂度均为 O ( 1 ) O(1) O(1),链表的头部作为栈顶
-
优雅的扩展,无需考虑栈满,需要额外的空间存储指针
接下来,我们首先测试上述实现的链表,以验证操作的有效性,然后利用实现的基本操作来解决实际算法问题。
3.1 顺序栈的应用
首先初始化一个顺序栈 stack
,然后测试相关操作:
初始化一个最大长度为4的栈
收集整理了一份《2024年最新Python全套学习资料》免费送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Python知识点,真正体系化!
份《2024年最新Python全套学习资料》免费送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。**
[外链图片转存中…(img-UHqqonHk-1726132825751)]
[外链图片转存中…(img-hD9KQA4p-1726132825752)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Python知识点,真正体系化!