02-栈与队列
💡 核心结论
栈(Stack)
特性:LIFO(后进先出),只能在栈顶操作
操作:push、pop、peek 全部O(1)
实现:数组栈(缓存友好)或链式栈(动态大小)
应用:函数调用、表达式求值、括号匹配、撤销操作
关键:限制访问顺序,强制后进先出
队列(Queue)
特性:FIFO(先进先出),队尾入队头出
操作:enqueue、dequeue、front 全部O(1)
循环队列:用模运算实现,需要一个空位区分满和空
应用:任务调度、BFS、消息队列、打印队列
关键:公平性,先到先服务
实现对比
实现方式 |
优点 |
缺点 |
|---|---|---|
数组栈/队列 |
缓存友好、实现简单 |
需要扩容或固定大小 |
链式栈/队列 |
动态大小、无需扩容 |
指针开销、缓存不友好 |
📚 栈(Stack)
特点
LIFO(Last In First Out)后进先出
只能在栈顶操作
主要操作:push、pop、peek
应用场景
函数调用栈
表达式求值
括号匹配
浏览器历史记录(后退)
撤销操作
时间复杂度
操作 |
复杂度 |
|---|---|
push |
O(1) |
pop |
O(1) |
peek |
O(1) |
search |
O(n) |
🎯 队列(Queue)
特点
FIFO(First In First Out)先进先出
队尾入队,队头出队
主要操作:enqueue、dequeue、front
应用场景
任务调度
广度优先搜索(BFS)
消息队列
打印队列
操作系统进程调度
循环队列
[front] [1] [2] [3] [4] [rear]
↑ ↑
front rear
当rear到末尾时,从头开始
[3] [4] [rear] [front] [1] [2]
↑ ↑
rear front
时间复杂度
操作 |
复杂度 |
|---|---|
enqueue |
O(1) |
dequeue |
O(1) |
front |
O(1) |
search |
O(n) |
🔧 栈的实现方式
数组栈
优点:
实现简单
缓存友好
缺点:
需要预分配空间或动态扩容
扩容时需要拷贝
链式栈
优点:
动态大小
无需扩容
缺点:
额外指针开销
缓存不友好
🔧 队列的实现方式
数组队列(循环队列)
使用模运算实现循环
需要一个空位区分满和空
front == rear:队列为空
(rear + 1) % capacity == front:队列满
链式队列
维护head和tail指针
无需考虑满的情况
动态大小
💡 经典问题
用栈实现括号匹配
def is_valid(s):
stack = []
pairs = {'(': ')', '[': ']', '{': '}'}
for char in s:
if char in pairs:
stack.append(char)
elif not stack or pairs[stack.pop()] != char:
return False
return not stack
# 测试
print(is_valid("()[]{}")) # True
print(is_valid("([)]")) # False
用栈计算后缀表达式
def eval_rpn(tokens):
stack = []
for token in tokens:
if token in ['+', '-', '*', '/']:
b = stack.pop()
a = stack.pop()
if token == '+': stack.append(a + b)
elif token == '-': stack.append(a - b)
elif token == '*': stack.append(a * b)
else: stack.append(int(a / b))
else:
stack.append(int(token))
return stack[0]
# 测试: ["2", "1", "+", "3", "*"] = (2 + 1) * 3 = 9
print(eval_rpn(["2", "1", "+", "3", "*"])) # 9
用队列实现BFS
from collections import deque
def bfs(graph, start):
visited = set()
queue = deque([start])
visited.add(start)
while queue:
node = queue.popleft()
print(node, end=' ')
for neighbor in graph[node]:
if neighbor not in visited:
visited.add(neighbor)
queue.append(neighbor)
# 测试
graph = {
'A': ['B', 'C'],
'B': ['A', 'D', 'E'],
'C': ['A', 'F'],
'D': ['B'],
'E': ['B', 'F'],
'F': ['C', 'E']
}
bfs(graph, 'A') # A B C D E F
单调栈
def next_greater_element(nums):
"""找每个元素右边第一个比它大的元素"""
result = [-1] * len(nums)
stack = [] # 单调递减栈
for i in range(len(nums)):
while stack and nums[i] > nums[stack[-1]]:
index = stack.pop()
result[index] = nums[i]
stack.append(i)
return result
# 测试
print(next_greater_element([2, 1, 2, 4, 3])) # [4, 2, 4, -1, -1]
📚 LeetCode练习
栈
队列
💡 最佳实践
选择合适的实现
大小固定 → 数组实现
大小动态 → 链表实现
异常处理
检查空栈/空队列
检查满队列
性能优化
循环队列避免元素移动
使用数组实现提高缓存命中
代码质量
封装良好
接口清晰
异常安全
💻 完整代码实现
Python 实现
栈实现
1"""
2栈的实现:数组栈和链式栈
3"""
4
5class ArrayStack:
6 """基于数组的栈"""
7
8 def __init__(self):
9 self._data = []
10
11 def push(self, val):
12 """入栈"""
13 self._data.append(val)
14
15 def pop(self):
16 """出栈"""
17 if self.is_empty():
18 raise IndexError('pop from empty stack')
19 return self._data.pop()
20
21 def peek(self):
22 """查看栈顶"""
23 if self.is_empty():
24 raise IndexError('peek from empty stack')
25 return self._data[-1]
26
27 def is_empty(self):
28 """是否为空"""
29 return len(self._data) == 0
30
31 def size(self):
32 """栈大小"""
33 return len(self._data)
34
35 def __str__(self):
36 return f"Stack({self._data})"
37
38
39class LinkedStack:
40 """基于链表的栈"""
41
42 class Node:
43 def __init__(self, val, next=None):
44 self.val = val
45 self.next = next
46
47 def __init__(self):
48 self._top = None
49 self._size = 0
50
51 def push(self, val):
52 """入栈"""
53 self._top = self.Node(val, self._top)
54 self._size += 1
55
56 def pop(self):
57 """出栈"""
58 if self.is_empty():
59 raise IndexError('pop from empty stack')
60 val = self._top.val
61 self._top = self._top.next
62 self._size -= 1
63 return val
64
65 def peek(self):
66 """查看栈顶"""
67 if self.is_empty():
68 raise IndexError('peek from empty stack')
69 return self._top.val
70
71 def is_empty(self):
72 return self._size == 0
73
74 def size(self):
75 return self._size
76
77
78if __name__ == '__main__':
79 print("=== 数组栈演示 ===\n")
80 stack = ArrayStack()
81
82 for i in range(1, 4):
83 stack.push(i)
84 print(f"push({i}): {stack}")
85
86 print(f"\npeek(): {stack.peek()}")
87
88 while not stack.is_empty():
89 print(f"pop(): {stack.pop()}")
90
91 print(f"\n栈是否为空: {stack.is_empty()}")
92
队列实现
1"""
2队列的实现:循环队列和链式队列
3"""
4
5class CircularQueue:
6 """循环队列(基于数组)"""
7
8 def __init__(self, capacity=5):
9 self._data = [None] * (capacity + 1) # 多一个位置区分满和空
10 self._front = 0
11 self._rear = 0
12 self._capacity = capacity + 1
13
14 def enqueue(self, val):
15 """入队"""
16 if self.is_full():
17 raise OverflowError('Queue is full')
18 self._data[self._rear] = val
19 self._rear = (self._rear + 1) % self._capacity
20
21 def dequeue(self):
22 """出队"""
23 if self.is_empty():
24 raise IndexError('dequeue from empty queue')
25 val = self._data[self._front]
26 self._front = (self._front + 1) % self._capacity
27 return val
28
29 def front(self):
30 """查看队首"""
31 if self.is_empty():
32 raise IndexError('front from empty queue')
33 return self._data[self._front]
34
35 def is_empty(self):
36 """是否为空"""
37 return self._front == self._rear
38
39 def is_full(self):
40 """是否已满"""
41 return (self._rear + 1) % self._capacity == self._front
42
43 def size(self):
44 """队列大小"""
45 return (self._rear - self._front + self._capacity) % self._capacity
46
47 def __str__(self):
48 if self.is_empty():
49 return "Queue([])"
50 items = []
51 i = self._front
52 while i != self._rear:
53 items.append(self._data[i])
54 i = (i + 1) % self._capacity
55 return f"Queue({items})"
56
57
58class LinkedQueue:
59 """链式队列"""
60
61 class Node:
62 def __init__(self, val, next=None):
63 self.val = val
64 self.next = next
65
66 def __init__(self):
67 self._head = None
68 self._tail = None
69 self._size = 0
70
71 def enqueue(self, val):
72 """入队"""
73 new_node = self.Node(val)
74 if self._tail is None:
75 self._head = self._tail = new_node
76 else:
77 self._tail.next = new_node
78 self._tail = new_node
79 self._size += 1
80
81 def dequeue(self):
82 """出队"""
83 if self.is_empty():
84 raise IndexError('dequeue from empty queue')
85 val = self._head.val
86 self._head = self._head.next
87 if self._head is None:
88 self._tail = None
89 self._size -= 1
90 return val
91
92 def front(self):
93 """查看队首"""
94 if self.is_empty():
95 raise IndexError('front from empty queue')
96 return self._head.val
97
98 def is_empty(self):
99 return self._size == 0
100
101 def size(self):
102 return self._size
103
104
105# 双端队列
106class Deque:
107 """双端队列"""
108
109 def __init__(self):
110 self._data = []
111
112 def add_front(self, val):
113 """前端添加"""
114 self._data.insert(0, val)
115
116 def add_rear(self, val):
117 """后端添加"""
118 self._data.append(val)
119
120 def remove_front(self):
121 """前端删除"""
122 if self.is_empty():
123 raise IndexError('remove from empty deque')
124 return self._data.pop(0)
125
126 def remove_rear(self):
127 """后端删除"""
128 if self.is_empty():
129 raise IndexError('remove from empty deque')
130 return self._data.pop()
131
132 def is_empty(self):
133 return len(self._data) == 0
134
135
136if __name__ == '__main__':
137 print("=== 循环队列演示 ===\n")
138 queue = CircularQueue(5)
139
140 print("入队: 1, 2, 3")
141 for i in range(1, 4):
142 queue.enqueue(i)
143 print(f"enqueue({i}): {queue}")
144
145 print(f"\nfront(): {queue.front()}")
146 print(f"size(): {queue.size()}")
147
148 print(f"\ndequeue(): {queue.dequeue()}")
149 print(f"队列: {queue}")
150
151 print(f"\n入队: 4, 5")
152 queue.enqueue(4)
153 queue.enqueue(5)
154 print(f"队列: {queue}")
155
C++ 实现
栈实现
1/**
2 * 栈的实现:数组栈和链式栈
3 */
4
5#include <iostream>
6#include <stdexcept>
7
8// ========== 数组栈 ==========
9template<typename T>
10class ArrayStack {
11private:
12 T* data;
13 int capacity;
14 int top_index;
15
16public:
17 ArrayStack(int cap = 10) : capacity(cap), top_index(-1) {
18 data = new T[capacity];
19 }
20
21 ~ArrayStack() {
22 delete[] data;
23 }
24
25 void push(const T& val) {
26 if (top_index == capacity - 1) {
27 // 扩容
28 capacity *= 2;
29 T* newData = new T[capacity];
30 for (int i = 0; i <= top_index; i++) {
31 newData[i] = data[i];
32 }
33 delete[] data;
34 data = newData;
35 }
36 data[++top_index] = val;
37 }
38
39 T pop() {
40 if (isEmpty()) {
41 throw std::runtime_error("Pop from empty stack");
42 }
43 return data[top_index--];
44 }
45
46 T peek() const {
47 if (isEmpty()) {
48 throw std::runtime_error("Peek from empty stack");
49 }
50 return data[top_index];
51 }
52
53 bool isEmpty() const {
54 return top_index == -1;
55 }
56
57 int size() const {
58 return top_index + 1;
59 }
60
61 void print() const {
62 std::cout << "Stack[";
63 for (int i = 0; i <= top_index; i++) {
64 std::cout << data[i];
65 if (i < top_index) std::cout << ", ";
66 }
67 std::cout << "]" << std::endl;
68 }
69};
70
71
72// ========== 链式栈 ==========
73template<typename T>
74class LinkedStack {
75private:
76 struct Node {
77 T val;
78 Node* next;
79 Node(T v) : val(v), next(nullptr) {}
80 };
81
82 Node* top_node;
83 int stack_size;
84
85public:
86 LinkedStack() : top_node(nullptr), stack_size(0) {}
87
88 ~LinkedStack() {
89 while (!isEmpty()) {
90 pop();
91 }
92 }
93
94 void push(const T& val) {
95 Node* newNode = new Node(val);
96 newNode->next = top_node;
97 top_node = newNode;
98 stack_size++;
99 }
100
101 T pop() {
102 if (isEmpty()) {
103 throw std::runtime_error("Pop from empty stack");
104 }
105 Node* temp = top_node;
106 T val = temp->val;
107 top_node = top_node->next;
108 delete temp;
109 stack_size--;
110 return val;
111 }
112
113 T peek() const {
114 if (isEmpty()) {
115 throw std::runtime_error("Peek from empty stack");
116 }
117 return top_node->val;
118 }
119
120 bool isEmpty() const {
121 return stack_size == 0;
122 }
123
124 int size() const {
125 return stack_size;
126 }
127};
128
129
130int main() {
131 std::cout << "=== 数组栈演示 ===" << std::endl << std::endl;
132
133 ArrayStack<int> stack;
134
135 std::cout << "入栈: 1, 2, 3" << std::endl;
136 for (int i = 1; i <= 3; i++) {
137 stack.push(i);
138 std::cout << "push(" << i << "): ";
139 stack.print();
140 }
141
142 std::cout << "\npeek(): " << stack.peek() << std::endl;
143 std::cout << "size(): " << stack.size() << std::endl << std::endl;
144
145 std::cout << "出栈:" << std::endl;
146 while (!stack.isEmpty()) {
147 std::cout << "pop(): " << stack.pop() << std::endl;
148 }
149
150 std::cout << "\n栈是否为空: " << (stack.isEmpty() ? "是" : "否") << std::endl;
151
152 return 0;
153}
队列实现
1/**
2 * 队列的实现:循环队列和链式队列
3 */
4
5#include <iostream>
6#include <stdexcept>
7
8// ========== 循环队列 ==========
9template<typename T>
10class CircularQueue {
11private:
12 T* data;
13 int front_index;
14 int rear_index;
15 int capacity;
16
17public:
18 CircularQueue(int cap = 5) : capacity(cap + 1), front_index(0), rear_index(0) {
19 data = new T[capacity];
20 }
21
22 ~CircularQueue() {
23 delete[] data;
24 }
25
26 void enqueue(const T& val) {
27 if (isFull()) {
28 throw std::runtime_error("Queue is full");
29 }
30 data[rear_index] = val;
31 rear_index = (rear_index + 1) % capacity;
32 }
33
34 T dequeue() {
35 if (isEmpty()) {
36 throw std::runtime_error("Dequeue from empty queue");
37 }
38 T val = data[front_index];
39 front_index = (front_index + 1) % capacity;
40 return val;
41 }
42
43 T front() const {
44 if (isEmpty()) {
45 throw std::runtime_error("Front from empty queue");
46 }
47 return data[front_index];
48 }
49
50 bool isEmpty() const {
51 return front_index == rear_index;
52 }
53
54 bool isFull() const {
55 return (rear_index + 1) % capacity == front_index;
56 }
57
58 int size() const {
59 return (rear_index - front_index + capacity) % capacity;
60 }
61
62 void print() const {
63 std::cout << "Queue[";
64 if (!isEmpty()) {
65 int i = front_index;
66 while (i != rear_index) {
67 std::cout << data[i];
68 i = (i + 1) % capacity;
69 if (i != rear_index) std::cout << ", ";
70 }
71 }
72 std::cout << "]" << std::endl;
73 }
74};
75
76
77// ========== 链式队列 ==========
78template<typename T>
79class LinkedQueue {
80private:
81 struct Node {
82 T val;
83 Node* next;
84 Node(T v) : val(v), next(nullptr) {}
85 };
86
87 Node* head;
88 Node* tail;
89 int queue_size;
90
91public:
92 LinkedQueue() : head(nullptr), tail(nullptr), queue_size(0) {}
93
94 ~LinkedQueue() {
95 while (!isEmpty()) {
96 dequeue();
97 }
98 }
99
100 void enqueue(const T& val) {
101 Node* newNode = new Node(val);
102 if (tail == nullptr) {
103 head = tail = newNode;
104 } else {
105 tail->next = newNode;
106 tail = newNode;
107 }
108 queue_size++;
109 }
110
111 T dequeue() {
112 if (isEmpty()) {
113 throw std::runtime_error("Dequeue from empty queue");
114 }
115 Node* temp = head;
116 T val = temp->val;
117 head = head->next;
118 if (head == nullptr) {
119 tail = nullptr;
120 }
121 delete temp;
122 queue_size--;
123 return val;
124 }
125
126 T front() const {
127 if (isEmpty()) {
128 throw std::runtime_error("Front from empty queue");
129 }
130 return head->val;
131 }
132
133 bool isEmpty() const {
134 return queue_size == 0;
135 }
136
137 int size() const {
138 return queue_size;
139 }
140};
141
142
143int main() {
144 std::cout << "=== 循环队列演示 ===" << std::endl << std::endl;
145
146 CircularQueue<int> queue(5);
147
148 std::cout << "入队: 1, 2, 3" << std::endl;
149 for (int i = 1; i <= 3; i++) {
150 queue.enqueue(i);
151 std::cout << "enqueue(" << i << "): ";
152 queue.print();
153 }
154
155 std::cout << "\nfront(): " << queue.front() << std::endl;
156 std::cout << "size(): " << queue.size() << std::endl;
157
158 std::cout << "\ndequeue(): " << queue.dequeue() << std::endl;
159 std::cout << "队列: ";
160 queue.print();
161
162 std::cout << "\n入队: 4, 5" << std::endl;
163 queue.enqueue(4);
164 queue.enqueue(5);
165 std::cout << "队列: ";
166 queue.print();
167
168 return 0;
169}