目录
1. stack
关于stack是什么和怎么用这里不再介绍。
实现也只是贴代码(毕竟太简单)。
1.1. stack常用接口实现
这里stack的实现与数据结构阶段的stack实现不同,不会去详细实现底层的结构,而是直接套用其他的容器来实现。所以stack和queue不是容器,而是容器适配器(下面讲)。
namespace wt
{
template <class T, class container = deque<T>> // 第二个模板参数是容器,缺省值为deque(双端队列)
class stack
{
public:
stack() // 因为套用其他容器,可以使用他们自己的构造函数,所以stack的构造函数不用自己实现
{}
void push(const T& val)
{
_con.push_back(val);
}
void pop()
{
_con.pop_back();
}
const T& top()const
{
return _con.back();
}
int size()const
{
return _con.size();
}
bool empty()const
{
return _con.size() == 0;
}
private:
container _con;
};
}
2. queue
2.1. 常用接口模拟实现
namespace wt
{
template <class T, class container = deque<T>>
class queue
{
public:
void push(const T& val)
{
_con.push_back(val);
}
void pop()
{
_con.pop_front(); // 注意先进先出
}
T front()const
{
return _con.front();
}
int size()const
{
return _con.size();
}
bool empty()const
{
return _con.size() == 0;
}
private:
container _con;
};
}
3. 容器适配器
3.1. 适配器
适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。
3.2. STL标准库中stack和queue的底层结构
虽然stack和queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stack和队列只是对其他容器的接口进行了包装。
STL中stack和queue默认使用deque,比如:
至于什么是deque可以自己去了解。。。
4.stack&queueOJ题
4.1.最小栈
方法:
- 使用两个栈,一个用来放原始数据(s1),一个用来放最小值(s2)
- 入栈时如果s1放入的数比s2栈顶的小或相等,则将该数也放入s2,否则不放
- 出栈时如果s1栈顶的数等于s2的栈顶,则s1、s2一起出栈
代码如下:
class MinStack {
public:
MinStack()
{}
void push(int val) {
s1.push(val);
if(s2.empty()||val<=s2.top()) // s2为空或者入栈数小于等于s2栈顶
{
s2.push(val);
}
}
void pop() {
if(s1.top()==s2.top()) // s1.top等于s2.top时
s2.pop();
s1.pop();
}
int top() {
return s1.top();
}
int getMin() {
return s2.top(); // 返回s2栈顶
}
private:
stack<int> s1;
stack<int> s2;
};
4.2.栈的弹出、压入序列
方法:
- 使用一个栈来模拟 该序列的压入
- 当压入的数与弹出序列的数相等时,从栈中弹出该数,直到没有相等的数为止;否则继续压入
- 当该序列全部入栈后,如果栈为空则说明压入顺序对应该弹出顺序,否则不对应
代码如下:
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
stack<int> s;
size_t j = 0;
for(size_t i = 0; i < pushV.size(); ++i)
{
s.push(pushV[i]);
while(!s.empty()&&s.top()==popV[j]) // 当栈顶与弹出队列相等时,出栈
{
s.pop();
++j;
}
}
if(s.empty())
{
return true;
}
else
{
return false;
}
}
};
4.3. 逆波兰表达式求值
逆波兰表达式又叫做后缀表达式,逆波兰表达式把运算量写在前面,把算符写在后面。
方法:
- 用一个栈来存放数字,遍历vector,遇到数字就入栈
- 如果遇到符号则连续将两个数字出栈进行运算,将运算结果继续入栈
- 最后栈中就只会剩下最终运算的答案
代码如下:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> s;
for(const auto& str:tokens)
{
if(str == "+" || str == "-" || str == "*" || str == "/")
{
int right = s.top();
s.pop();
int left = s.top();
s.pop();
switch(str[0])
{
case '+':
{
s.push(left+right);
break;
}
case '-':
{
s.push(left-right);
break;
}
case '*':
{
s.push(left*right);
break;
}
case '/':
{
s.push(left/right);
break;
}
default:
assert(false);
}
}
else
{
s.push(stoi(str)); // 将字符串转化成数组入栈
}
}
return s.top();
}
};