数据结构算法 - 栈
栈
是一种操作受限的 线性表
,在我们平时的日常生活中,可以看到许多与之相似的场景。比 如一层一层叠起来的盘子
,我们网上叠的时候,是一个个一个向上叠加,我们在取的时候,也是从最上面一个一个拿走。不能从中间直接抽取
这种满足 先进者后出,后进者先出 的就是 栈
结构
因为只允许在 一端
插入和删除,所以这是一种操作受限的 线性表
在某些特定场景下,我们需要的这种数据结构只涉及在 一端的插入和删除
,并且数据满足先进先出,后进后出的特性的时候就应该首选栈这种数据结构
栈的抽象数据类型
ADT 栈(stack)
Data
线性表相同,具有相同的类型,相邻元素具有前驱和后继关系
Opreation
InitStack(*S): 初始化栈
DestroyStack(*S): 若栈存在,销毁
ClearStack(*S): 清空栈
StackEmpty(*S): 栈是否为空,空返回 true,否返回 false
GetTop(*S, e): 若 S 存在,用 e 返回栈顶的元素
Push(*S,e): 插入新元素 e 到栈顶
Pop(*S,*e): 删除栈顶元素,用 e 返回值
StackLenght(S): 返回栈的元素个数
endADT
栈既可以用数组实现,也可以用链表来实现。用数组实现的栈叫做顺序栈,用链表实现的栈叫做链式栈
不论是顺序栈还是链式栈,在入栈和出栈的过程中,只需要一两个临时变量存储空间,所以空间复杂度是 O(1)。由于只设计栈顶元素的数据操作,所以时间复杂度为 O(1)
顺序栈的动态扩容
顺序栈的动态扩容,和数组基本相同,在入栈的过程中,如果申请的存储空间不够了,那么需要对原始的空间进行扩容,这个时候就涉及到数据的搬移操作,最坏情况时间复杂度为 O(n)
需要注意的是,在大多数情况下,入栈操作需要的是 O(1) 的时间复杂度,在经过 n 个 O(1) 的入栈操作之后,需要集中触发一次时间复杂度为 O(n) 的搬移操作,所以平均情况时间复杂度为 O(1)
栈的具体应用
- 函数调用中,使用栈帧来保存函数变量
- 栈可以实现表达式的糗事
- 栈可以实现括号的匹配
- 利用辅助栈,可以实现浏览器的前进和后退功能