std::stack(栈)
在 C++ 中,std::stack
是标准模板库(STL)中的容器适配器,遵循**后进先出(LIFO,Last In First Out)**的原则。也就是说,最后插入的元素最先被访问。stack
本质上是对容器的一种封装,底层可以基于 std::deque
、std::vector
或 std::list
实现。
1. 基本概念
std::stack
是一个容器适配器,它限制了底层容器的操作,仅提供对栈的基本操作接口。常见的操作有:
push()
:将元素压入栈顶。pop()
:移除栈顶元素。top()
:访问栈顶元素。empty()
:检查栈是否为空。size()
:返回栈中元素的个数。
2. 栈的声明与初始化
std::stack
默认使用 std::deque
作为底层容器,但也可以使用 std::vector
或 std::list
。
使用默认容器(std::deque
):
#include <iostream>
#include <stack>
int main() {
std::stack<int> s; // 创建一个空栈
s.push(10); // 向栈中压入元素 10
s.push(20); // 向栈中压入元素 20
s.push(30); // 向栈中压入元素 30
std::cout << "Stack top element: " << s.top() << std::endl; // 输出栈顶元素
return 0;
}
使用 std::vector
或 std::list
作为底层容器:
#include <iostream>
#include <stack>
#include <vector>
#include <list>
int main() {
std::stack<int, std::vector<int>> s1; // 使用 vector 作为底层容器
std::stack<int, std::list<int>> s2; // 使用 list 作为底层容器
s1.push(1);
s2.push(2);
std::cout << "s1 top: " << s1.top() << std::endl;
std::cout << "s2 top: " << s2.top() << std::endl;
return 0;
}
3. 常用操作
3.1 push()
向栈顶添加一个元素。
std::stack<int> s;
s.push(10); // 栈现在包含元素 10
s.push(20); // 栈现在包含元素 10, 20 (20 在栈顶)
3.2 pop()
移除栈顶元素,注意此操作并不会返回被移除的元素,若需要访问栈顶元素可以先调用 top()
。
std::stack<int> s;
s.push(10);
s.push(20);
s.pop(); // 移除栈顶元素,栈顶元素现在是 10
3.3 top()
返回栈顶元素的引用(不删除),可以通过它来访问或修改栈顶的元素。
std::stack<int> s;
s.push(10);
s.push(20);
int topElement = s.top(); // 访问栈顶元素,不会删除
std::cout << "Top element: " << topElement << std::endl;
3.4 empty()
判断栈是否为空,返回布尔值。
std::stack<int> s;
std::cout << std::boolalpha << s.empty() << std::endl; // 输出 true,因为栈为空
3.5 size()
返回栈中元素的个数。
std::stack<int> s;
s.push(10);
s.push(20);
std::cout << "Stack size: " << s.size() << std::endl; // 输出 2
4. 完整示例
以下是使用 std::stack
的一个完整示例,它展示了栈的基本操作。
#include <iostream>
#include <stack>
int main() {
std::stack<int> s;
// 向栈中压入元素
s.push(10);
s.push(20);
s.push(30);
// 栈的大小
std::cout << "Stack size: " << s.size() << std::endl;
// 访问栈顶元素
std::cout << "Top element: " << s.top() << std::endl;
// 移除栈顶元素
s.pop();
std::cout << "After pop, new top element: " << s.top() << std::endl;
// 栈是否为空
if (!s.empty()) {
std::cout << "Stack is not empty" << std::endl;
}
return 0;
}
输出:
Stack size: 3
Top element: 30
After pop, new top element: 20
Stack is not empty
5. 使用 std::stack
实现常见问题
5.1 括号匹配问题
使用栈可以轻松实现括号匹配的算法。
#include <iostream>
#include <stack>
#include <string>
bool isValid(const std::string& s) {
std::stack<char> stack;
for (char c : s) {
if (c == '(' || c == '[' || c == '{') {
stack.push(c);
} else {
if (stack.empty()) return false;
char top = stack.top();
if ((c == ')' && top == '(') ||
(c == ']' && top == '[') ||
(c == '}' && top == '{')) {
stack.pop();
} else {
return false;
}
}
}
return stack.empty();
}
int main() {
std::string s = "{[()]}";
if (isValid(s)) {
std::cout << "Valid parentheses" << std::endl;
} else {
std::cout << "Invalid parentheses" << std::endl;
}
return 0;
}
输出:
Valid parentheses
5.2 使用栈实现整数反转
我们可以使用栈将整数中的每一位压入栈中,然后按顺序弹出,以实现整数反转。
#include <iostream>
#include <stack>
void reverseNumber(int n) {
std::stack<int> s;
while (n > 0) {
s.push(n % 10); // 将每一位压入栈中
n /= 10;
}
while (!s.empty()) {
std::cout << s.top(); // 输出栈顶元素
s.pop(); // 移除栈顶元素
}
std::cout << std::endl;
}
int main() {
int num = 12345;
reverseNumber(num); // 输出:54321
return 0;
}
输出:
54321
6. std::stack
的底层实现
std::stack
本质上是一个容器适配器,它封装了一个底层容器,默认情况下底层容器是 std::deque
。你可以选择使用 std::vector
或 std::list
作为底层容器。
std::deque
:默认的底层容器,双端队列,支持在两端进行高效的插入和删除。std::vector
:动态数组,栈顶的操作是高效的,但在头部插入或删除较慢。std::list
:双向链表,支持在头尾快速插入删除元素,但不支持随机访问。
7. 注意事项
- 栈不支持遍历:
std::stack
是一个容器适配器,不能直接像std::vector
或std::list
那样进行遍历,因为它只暴露了栈顶的访问权限。如果需要遍历栈中的所有元素,可以通过pop()
一次访问一个元素。 - 底层容器的选择:
std::deque
是默认的底层容器,但你也可以根据需求选择其他容器(如std::vector
或std::list
)。一般来说,如果只关心栈顶的操作,可以直接使用默认的std::deque
。