1. 基本概念
-
堆栈(Stack):
- 堆栈是一种**后进先出(LIFO,Last In First Out)**的数据结构,即最后进入栈的元素最先被取出。
- 你可以将堆栈看作一个垂直的容器,新元素压入栈顶,取出时总是从栈顶取。
- 栈的基本操作:
push
:将元素推入栈顶。pop
:从栈顶弹出元素。peek
:查看栈顶元素,但不移除它。
-
队列(Queue):
- 队列是一种**先进先出(FIFO,First In First Out)**的数据结构,即最早进入队列的元素最先被取出。
- 队列的结构就像一个排队的队列,新元素总是加入队列的尾部,元素从队列的头部出队。
- 队列的基本操作:
enqueue
:将元素添加到队列的尾部。dequeue
:从队列的头部移除元素。peek
:查看队列头部的元素,但不移除它。
2. 操作顺序
-
堆栈(Stack):
- 操作是从栈顶进行的,遵循 "后进先出"(LIFO)原则。
- 例如:
- 执行
push(1)
-> 栈:[1] - 执行
push(2)
-> 栈:[1, 2] - 执行
pop()
-> 返回 2,栈:[1] - 执行
pop()
-> 返回 1,栈:[]
- 执行
-
队列(Queue):
- 操作是从队头进行的,遵循 "先进先出"(FIFO)原则。
- 例如:
- 执行
enqueue(1)
-> 队列:[1] - 执行
enqueue(2)
-> 队列:[1, 2] - 执行
dequeue()
-> 返回 1,队列:[2] - 执行
dequeue()
-> 返回 2,队列:[]
- 执行
3. 内存管理
-
堆栈:
- 堆栈通常是连续的内存区域,存储的数据通常是局部变量或函数调用的参数和返回地址。
- 内存管理由操作系统自动完成,函数调用结束时自动清除栈上的数据。
-
队列:
- 队列通常是动态分配的内存空间,支持元素在队列两端的进出操作。
- 内存管理方式取决于队列的实现,可能是数组或链表。
4. 实现方式
-
堆栈:
- 栈可以用数组或链表实现。使用数组实现时,栈的大小是固定的;使用链表时,栈的大小可以动态扩展。
- 主要支持
push
和pop
操作。
-
队列:
- 队列可以用数组或链表实现。数组实现时需要额外注意队列头和尾的指针管理,链表实现时可以方便地实现动态扩展。
- 主要支持
enqueue
和dequeue
操作。
5. 应用场景
-
堆栈(Stack):
- 函数调用栈:在编程语言中,函数调用时会使用堆栈来保存局部变量、函数参数和返回地址。栈的后进先出特点可以保证函数调用的正确顺序。
- 表达式求值:比如算术表达式的求值(中缀转后缀、前缀表达式求值等)常使用栈来存储操作符。
- 回溯算法:DFS(深度优先搜索)等算法通常使用栈来存储当前路径的状态,实现回溯。
-
队列(Queue):
- 任务调度:操作系统的任务调度器通常使用队列来管理等待执行的进程或任务,保证任务按顺序执行。
- 广度优先搜索(BFS):BFS 遍历算法使用队列来实现层次遍历,确保按层访问图中的节点。
- 流量控制:如生产者-消费者问题、消息队列等应用场景。
6. 空间复杂度和时间复杂度
- 堆栈:
- 空间复杂度:O(n),栈需要存储n个元素。
- 时间复杂度:
push
和pop
操作都是 O(1)。peek
操作也是 O(1)。
- 队列:
- 空间复杂度:O(n),队列需要存储n个元素。
- 时间复杂度:
enqueue
和dequeue
操作都是 O(1)。peek
操作也是 O(1)。
7. 区别总结
特性 | 堆栈(Stack) | 队列(Queue) |
---|---|---|
操作顺序 | 后进先出(LIFO) | 先进先出(FIFO) |
基本操作 | push (入栈),pop (出栈),peek (查看栈顶元素) | enqueue (入队),dequeue (出队),peek (查看队头元素) |
实现方式 | 可以用数组或链表实现 | 可以用数组或链表实现 |
内存管理 | 自动管理,栈的内存通常由操作系统管理 | 动态管理,可能需要手动管理内存(如循环队列实现) |
应用场景 | 函数调用栈、表达式求值、回溯算法等 | 任务调度、广度优先搜索(BFS)、消息队列等 |
时间复杂度 | push 、pop 、peek 都是 O(1) | enqueue 、dequeue 、peek 都是 O(1) |
空间复杂度 | O(n) | O(n) |
联系:
- 都是线性数据结构:堆栈和队列都是线性数据结构,意味着它们的元素是按顺序存储的,允许按特定顺序访问和操作。
- 都可以用数组或链表实现:两者都可以用静态数组或动态链表来实现,具体实现方式影响其内存管理和效率。
- 都具有特定的访问规则:堆栈具有后进先出的规则,而队列具有先进先出的规则。
总结起来,堆栈和队列在数据访问顺序上有根本的区别,堆栈更适合用于需要反向访问的场景(如回溯、递归),而队列适合需要按顺序处理数据的场景(如任务调度、BFS)。