栈
- 什么是栈
- 入栈与出栈
- LIFO 特性
- 调用栈
- 应用场景
什么是栈
栈是一种数据呈线性排列的数据结构,但有个特殊限制:只能在一端(栈顶)进行数据的添加和删除。
把栈想象成一摞盘子:你只能把新盘子放在最上面,也只能从最上面拿走盘子——不可能从中间抽一个出来。
┌──────┐
│ Red │ ← 栈顶(最后放入的,最先取出)
├──────┤
│Green │
├──────┤
│ Blue │ ← 栈底(最先放入的,最后取出)
└──────┘
入栈与出栈
- 入栈(push):把数据放到栈顶
- 出栈(pop):把栈顶的数据取出来
入栈过程:
放入 Blue 放入 Green 放入 Red
┌──────┐ ┌──────┐ ┌──────┐
│ Blue │ │Green │ │ Red │ ← 栈顶
└──────┘ ├──────┤ ├──────┤
│ Blue │ │Green │
└──────┘ ├──────┤
│ Blue │
└──────┘
出栈过程:
取出 Red 取出 Green 取出 Blue
┌──────┐ ┌──────┐ (空)
│Green │ ← 栈顶 │ Blue │ ← 栈顶
├──────┤ └──────┘
│ Blue │
└──────┘
Python 实现:
stack = []
# 入栈
stack.append("Blue")
stack.append("Green")
stack.append("Red")
print(stack) # ['Blue', 'Green', 'Red']
# 出栈
top = stack.pop()
print(top) # Red(最后入栈的,最先出栈)
print(stack) # ['Blue', 'Green']
LIFO 特性
栈的核心特性是 LIFO(Last In First Out,后进先出):最后放入的数据,最先被取出来。
入栈顺序: Blue → Green → Red
出栈顺序: Red → Green → Blue(完全反过来!)
想访问栈中间的数据?不行,必须先把上面的数据一个个出栈,直到目标数据到达栈顶。
调用栈
计算机在内部使用被称为调用栈的栈来管理函数调用。当你调用一个函数时,计算机把函数的局部变量和返回地址压入栈;函数返回时,再弹出。
def greet(name):
print "hello, " + name
greet2(name) # ← 调用 greet2,greet 暂停
print "bye"
bye() # ← 调用 bye
调用 greet("maggie") 时的调用栈变化:
栈顶 → greet2("maggie") ← greet2 执行中
greet("maggie") ← greet 暂停等待
栈顶 → greet("maggie") ← greet2 返回后,greet 恢复
递归函数也使用调用栈——每层递归调用都会压入栈中,这也是为什么递归太深会导致栈溢出。
应用场景
- 函数调用管理:所有编程语言的函数调用都依赖调用栈
- 括号匹配:读到左括号入栈,读到右括号出栈,检查是否匹配
字符串: ( A B ( C ( D E ) F ) ( G ( ( H ) I J ) K ) )
处理过程:
( → 入栈 栈: (
( → 入栈 栈: ( (
( → 入栈 栈: ( ( (
) → 出栈 栈: ( ( ← 与最近的 ( 匹配
...
- 撤销操作(Undo):编辑器的撤销功能用栈保存历史操作
- 表达式求值:后缀表达式的计算使用栈
- 深度优先搜索:候补顶点的管理使用栈(LIFO 特性恰好匹配 DFS 的需求)
- 浏览器后退:访问的页面依次入栈,点后退就出栈
小结
- 栈只能在一端(栈顶)操作,后进先出(LIFO)
- 入栈(push)和出栈(pop)的时间复杂度都是 O(1)
- 调用栈是栈最重要的应用,管理函数调用和递归
- 只要问题涉及「最后处理的先用到」,就考虑用栈