好的!既然你提到了 C++ 标准库中的容器适配器 <stack>
,我将为你详细讲解它的用法,包括基本概念、特性、功能以及实用示例。<stack>
是 C++ STL 中的一种栈容器适配器,遵循“后进先出”(LIFO, Last In First Out)的原则。它基于其他底层容器(如 <deque>
)实现,提供简洁的栈操作接口。以下是完整的内容,适合学习和实践。
C++ 标准库:<stack>
<stack>
是一个模板类,封装了栈的行为。它的主要特点是:
- LIFO 结构:元素按后进先出的顺序访问。
- 适配器设计:基于底层容器(如
<deque>
、<vector>
、<list>
)实现。 - 简单接口:仅提供栈顶操作和基本管理功能。
- 动态大小:大小随元素增减动态调整。
包含头文件
#include <stack>
#include <iostream> // 通常配合使用
定义格式
std::stack<类型, 底层容器> 变量名;
类型
:栈中元素的数据类型(如int
、double
、std::string
)。底层容器
:可选,默认是std::deque<T>
,也可以指定为std::vector<T>
或std::list<T>
。
基本用法
1. 声明和初始化
#include <stack>
#include <iostream>
int main() {
std::stack<int> stk; // 默认使用 deque 作为底层容器
stk.push(1); // 入栈
stk.push(2);
stk.push(3);
std::cout << "Top: " << stk.top() << std::endl; // 输出:3
return 0;
}
- 不支持直接用初始化列表,需逐个
push
。
2. 入栈和出栈
#include <stack>
#include <iostream>
int main() {
std::stack<int> stk;
stk.push(10); // 入栈
stk.push(20);
stk.push(30);
std::cout << "Original top: " << stk.top() << std::endl; // 输出:30
stk.pop(); // 出栈
std::cout << "After pop: " << stk.top() << std::endl; // 输出:20
return 0;
}
push()
:O(1),将元素压入栈顶。pop()
:O(1),移除栈顶元素(不返回)。
3. 访问栈顶
#include <stack>
#include <iostream>
int main() {
std::stack<std::string> stk;
stk.push("Apple");
stk.push("Banana");
std::cout << "Top: " << stk.top() << std::endl; // 输出:Banana
return 0;
}
top()
:O(1),返回栈顶元素的引用。- 无随机访问,只能访问栈顶。
4. 大小和状态
#include <stack>
#include <iostream>
int main() {
std::stack<int> stk;
std::cout << "Empty? " << (stk.empty() ? "Yes" : "No") << std::endl; // 输出:Yes
std::cout << "Size: " << stk.size() << std::endl; // 输出:0
stk.push(1);
stk.push(2);
std::cout << "Empty? " << (stk.empty() ? "Yes" : "No") << std::endl; // 输出:No
std::cout << "Size: " << stk.size() << std::endl; // 输出:2
return 0;
}
empty()
:O(1),检查栈是否为空。size()
:O(1),返回当前元素数。
5. 指定底层容器
#include <stack>
#include <vector>
#include <iostream>
int main() {
std::stack<int, std::vector<int>> stk; // 使用 vector 作为底层容器
stk.push(10);
stk.push(20);
stk.push(30);
std::cout << "Top: " << stk.top() << std::endl; // 输出:30
stk.pop();
std::cout << "New top: " << stk.top() << std::endl; // 输出:20
return 0;
}
- 默认用
<deque>
,但可改为<vector>
或<list>
。
与其他容器的对比
特性 | std::stack | std::vector | std::deque |
---|---|---|---|
数据结构 | 栈(LIFO) | 动态数组 | 双端队列 |
访问方式 | 仅栈顶 | 随机访问 | 随机访问 |
插入/删除 | 仅顶部 O(1) | 尾 O(1),其他 O(n) | 首尾 O(1),其他 O(n) |
底层容器 | 可选(默认 deque) | 自身 | 自身 |
迭代器 | 不支持 | 支持 | 支持 |
注意事项
- 接口限制:无迭代器,无法遍历所有元素,只能操作栈顶。
- 异常安全:
top()
或pop()
在空栈上调用是未定义行为,需先检查empty()
。 - 底层容器选择:
<deque>
(默认):首尾操作高效。<vector>
:尾部操作高效,节省内存。<list>
:插入/删除高效,但内存开销大。
- 性能:依赖底层容器,默认
<deque>
提供最佳平衡。
实用示例:括号匹配
以下是一个经典应用:检查括号是否匹配。
#include <stack>
#include <iostream>
#include <string>
bool isValid(const std::string& s) {
std::stack<char> stk;
for (char c : s) {
if (c == '(' || c == '[' || c == '{') {
stk.push(c);
} else if (c == ')' || c == ']' || c == '}') {
if (stk.empty()) return false;
char top = stk.top();
stk.pop();
if ((c == ')' && top != '(') ||
(c == ']' && top != '[') ||
(c == '}' && top != '{')) {
return false;
}
}
}
return stk.empty(); // 栈空表示匹配
}
int main() {
std::string expr1 = "{[()]}";
std::string expr2 = "{[}";
std::cout << expr1 << " is " << (isValid(expr1) ? "valid" : "invalid") << std::endl;
std::cout << expr2 << " is " << (isValid(expr2) ? "valid" : "invalid") << std::endl;
return 0;
}
输出:
{[()]} is valid
{[} is invalid
小练习
以下是一个基于 <stack>
的练习题,你可以尝试:
问题:
写一个 C++ 程序:
- 定义一个
std::stack<int>
。 - 依次压入 10、20、30、40。
- 输出栈顶元素。
- 弹出两个元素。
- 输出剩余元素个数和栈顶元素。
参考答案(你可以先尝试)
#include <stack>
#include <iostream>
int main() {
std::stack<int> stk;
// 压入元素
stk.push(10);
stk.push(20);
stk.push(30);
stk.push(40);
// 输出栈顶
std::cout << "Top: " << stk.top() << std::endl; // 输出:40
// 弹出两个元素
stk.pop();
stk.pop();
// 输出剩余元素个数和栈顶
std::cout << "Size: " << stk.size() << std::endl; // 输出:2
std::cout << "New top: " << stk.top() << std::endl; // 输出:20
return 0;
}
下一步
- 如果你想试试这个练习,请写下你的代码,我会帮你检查。
- 如果你想要更复杂的内容(如逆波兰表达式计算、自定义底层容器),或者设计
<stack>
的测验题,请告诉我! - 你也可以提出具体问题,如“如何用
<stack>
实现递归?”或“<stack>
和<deque>
的区别?”。
现在,你想做什么?试试练习,还是有其他需求?
发表回复