一. 栈stack
stack也是一种线性结构, 其特点是LIFO, 后进先出. 最后进入栈的元素先出栈
stack是一个操作受限的线性结构, 底层空间可以是连续的也可以是不连续的
只需向上层提供对stack的入栈, 出栈, 取栈顶, 判断栈为空, 栈的大小等操作
二. STL中的stack
STL中对栈的描述:
1.stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行
元素的插入与提取操作; 容器适配器即是对特定类封装作为其底层的容器,并提供一组特定
的成员函数来访问其元素2.stack的底层容器可以是任何容器类模板或者一些其他特定的容器类,这些容器类应该支持以下操作:
empty:判空操作
back:获取尾部元素操作
push_back:尾部插入元素操作
pop_back:尾部删除元素操作3.标准容器vector、deque、list均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器,
默认情况下使用deque
1. STL中对栈的定义是容器适配器, 什么是容器适配器
适配器是一种设计模式, 该模式是将一个类的接口转换成客户希望的另外一个接口
简单来说 vector, list, deque 都有自己的底层空间结构, 而容器适配器(stack, queue)只是将其他已有的
容器类进行了封装, 并提供了自己的接口
2. vector, deque, list都可以作为底层容器
对于stack来说, 需要提供的接口是主要是push(入栈)和pop(出栈)和top(取栈顶元素), 底层容器最好提供高效的接口
vector不考虑增容时支持O(1)的push_back, pop_back和随机访问
list支持O(1)的push_back, pop_back和back
deque双端队列是一种复杂的数据结构,底层空间由多个不连续的存储块构成, 支持随机访问, 支持O(1)的头尾修改
3. C++选用deque作为STL stack, queue底层的容器
1. stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。
2. 在stack中元素增长时,deque比vector的效率高;queue中的元素增长时,deque不仅效率高,而且内
存使用率高
三. 实现一个Stack
自己实现一个类似STL中的栈, 底层容器使用上一次写的Vector
template<class T, class Container = Vector<T>>
class Stack{
public:
Stack(){} // 构造, 自动调用Vector的构造
T Top(){
return _con.back(); // 返回Vector的最后一个元素
}
void Push(const T& x){ // Push_Back到Vector
_con.push_back(x);
}
void Pop(){
_con.pop_back(); // 删除Vector的尾部元素
}
bool Empty(){
return _con.size() == 0; // Vector的size是否为0
}
int Size(){
return _con.size(); // 返回Vector的size
}
private:
Container _con;
};
四. 有关栈的简单笔试题
1. LeetCode 20. 有效的括号 https://leetcode-cn.com/problems/valid-parentheses/
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
1.左括号必须用相同类型的右括号闭合。
2.左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
思路: 使用一个栈, 遍历字符串, 遇到左括号入栈, 遇到右括号和栈顶元素比较
bool isValid(string s) {
if (s.size() % 2 != 0) return false;
std::stack<int> _stack;
for(auto ch : s){
if (ch == '(' || ch == '[' || ch == '{'){
_stack.push(ch); // 左括号入栈
}
else{
if (_stack.empty()) return false;
char left = _stack.top(); // 右括号比较栈顶元素
_stack.pop();
if (ch == ')' && left != '(')
return false;
else if (ch == ']' && left != '[')
return false;
else if (ch == '}' && left != '{')
return false;
}
}
if (!_stack.empty())
return false;
else
return true;
}
2. LeetCode 155. 最小栈 https://leetcode-cn.com/problems/min-stack/submissions/
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) -- 将元素 x 推入栈中。
pop() -- 删除栈顶的元素。
top() -- 获取栈顶元素。
getMin() -- 检索栈中的最小元素。
思路: 使用两个栈, 一个存数据, 一个存当前数据栈中的最小值(一定要<=), 存最小值相当于存当前数据入栈时的最小值
class MinStack {
public:
MinStack() {
}
void push(int x) {
_eleStack.push(x); // 数据直接加入数据栈
if (_minStack.empty() || x <= _minStack.top()) // = 很重要, 不然pop会有问题
_minStack.push(x);
}
void pop() {
if (_minStack.top() == _eleStack.top()){ // 如果删除的数据是最小的要从最小栈删除
_minStack.pop();
}
_eleStack.pop();
}
int top() {
return _eleStack.top();
}
int getMin() {
return _minStack.top();
}
private:
std::stack<int> _eleStack; // 数据栈
std::stack<int> _minStack; // 存最小值的栈
};