栈
概念讲解
什么是栈?
栈(Stack)是一种后进先出(LIFO, Last In First Out)的数据结构。
类比: 一摞盘子,只能从顶部拿取
栈的基本操作
| 操作 | 说明 | 时间复杂度 |
|---|---|---|
| push | 入栈(添加元素到栈顶) | O(1) |
| pop | 出栈(移除栈顶元素) | O(1) |
| top | 获取栈顶元素 | O(1) |
| empty | 判断栈是否为空 | O(1) |
| size | 获取栈的大小 | O(1) |
实现方式
数组实现
1234567891011121314151617181920212223const int N = 1005;
int stk[N]; // 栈数组
int tt = 0; // 栈顶指针
// 入栈
void push(int x) {
stk[++tt] = x;
}
// 出栈
void pop() {
tt--;
}
// 获取栈顶
int top() {
return stk[tt];
}
// 判断是否为空
bool empty() {
return tt == 0;
}STL stack
12345678910111213141516171819#include <stack>
using namespace std;
stack<int> stk;
// 入栈
stk.push(1);
// 出栈
stk.pop();
// 获取栈顶
int x = stk.top();
// 判断是否为空
if (stk.empty()) { ... }
// 获取大小
int sz = stk.size();经典应用
1. 括号匹配
问题: 判断括号序列是否合法。
1234567891011121314151617181920bool isValid(string s) {
stack<char> stk;
for (char c : s) {
if (c == '(' || c == '[' || c == '{') {
stk.push(c);
} else {
if (stk.empty()) return false;
char top = stk.top();
stk.pop();
if (c == ')' && top != '(') return false;
if (c == ']' && top != '[') return false;
if (c == '}' && top != '{') return false;
}
}
return stk.empty();
}2. 表达式求值
问题: 计算中缀表达式的值。
12345678910111213141516171819202122232425262728293031323334int calculate(string s) {
stack<int> nums;
stack<char> ops;
for (int i = 0; i < s.size(); i++) {
if (isdigit(s[i])) {
int num = 0;
while (i < s.size() && isdigit(s[i])) {
num = num * 10 + (s[i] - '0');
i++;
}
i--;
nums.push(num);
} else if (s[i] == '(') {
ops.push('(');
} else if (s[i] == ')') {
while (ops.top() != '(') {
calc(nums, ops);
}
ops.pop(); // 弹出 '('
} else {
while (!ops.empty() && priority(ops.top()) >= priority(s[i])) {
calc(nums, ops);
}
ops.push(s[i]);
}
}
while (!ops.empty()) {
calc(nums, ops);
}
return nums.top();
}3. 单调栈
问题: 找到每个元素右边第一个比它大的元素。
123456789101112131415vector<int> nextGreater(vector<int>& nums) {
int n = nums.size();
vector<int> result(n, -1);
stack<int> stk;
for (int i = 0; i < n; i++) {
while (!stk.empty() && nums[stk.top()] < nums[i]) {
result[stk.top()] = nums[i];
stk.pop();
}
stk.push(i);
}
return result;
}考点分析
初赛考查方式
选择题: 栈的特性
- 例:栈的特点是什么?
- 答:后进先出(LIFO)
程序阅读: 理解栈的操作过程
完善程序: 补全栈相关代码
常见题型
- 括号匹配
- 表达式求值
- 单调栈
例题精讲
例题 1:括号匹配
题目: 判断括号序列 "([])" 是否合法。
解答:
1. 遇到 '(',入栈
2. 遇到 '[',入栈
3. 遇到 ']',匹配栈顶 '[',出栈
4. 遇到 ')',匹配栈顶 '(',出栈
5. 栈为空,合法例题 2:栈的应用
题目: 用两个栈实现队列。
解答:
12345678910111213141516171819class MyQueue {
stack<int> in, out;
void push(int x) {
in.push(x);
}
int pop() {
if (out.empty()) {
while (!in.empty()) {
out.push(in.top());
in.pop();
}
}
int x = out.top();
out.pop();
return x;
}
};练习题
基础题
- 栈的特点是什么?
查看答案
栈的特点是后进先出(LIFO, Last In First Out)。
最后入栈的元素最先出栈,就像一摞盘子,只能从顶部拿取。
- 写出栈的五个基本操作。
查看答案
- push(x):入栈,将元素 x 添加到栈顶
- pop():出栈,移除栈顶元素
- top():获取栈顶元素(不移除)
- empty():判断栈是否为空
- size():获取栈中元素个数
所有操作时间复杂度均为 O(1)。
- 用数组实现一个栈。
查看答案
1234567891011121314151617181920212223const int N = 1005;
int stk[N]; // 栈数组
int tt = 0; // 栈顶指针
// 入栈
void push(int x) {
stk[++tt] = x;
}
// 出栈
void pop() {
tt--;
}
// 获取栈顶
int top() {
return stk[tt];
}
// 判断是否为空
bool empty() {
return tt == 0;
}提高题
- 洛谷 P1739 表达式括号匹配
查看答案
使用栈匹配括号:
12345678910111213141516171819202122232425#include <iostream>
#include <stack>
using namespace std;
int main() {
string s;
cin >> s;
stack<char> stk;
for (char c : s) {
if (c == '@') break;
if (c == '(') {
stk.push(c);
} else if (c == ')') {
if (stk.empty()) {
cout << "NO" << endl;
return 0;
}
stk.pop();
}
}
cout << (stk.empty() ? "YES" : "NO") << endl;
return 0;
}- 洛谷 P1449 后缀表达式
查看答案
使用栈计算后缀表达式:
12345678910111213141516171819202122232425262728293031#include <iostream>
#include <stack>
using namespace std;
int main() {
string s;
cin >> s;
stack<int> stk;
for (int i = 0; i < s.size(); i++) {
if (isdigit(s[i])) {
int num = 0;
while (isdigit(s[i])) {
num = num * 10 + (s[i] - '0');
i++;
}
stk.push(num);
i--;
} else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/') {
int b = stk.top(); stk.pop();
int a = stk.top(); stk.pop();
if (s[i] == '+') stk.push(a + b);
else if (s[i] == '-') stk.push(a - b);
else if (s[i] == '*') stk.push(a * b);
else stk.push(a / b);
}
}
cout << stk.top() << endl;
return 0;
}易错点
⚠️ 注意:
- 栈为空时不能 pop 或 top
- 数组栈要注意大小限制
- STL stack 的 pop 不返回值
- 单调栈要维护栈内元素的单调性