1.栈的定义
我们可以看到模板参数里面有一个容器适配器 ,什么是适配器?比如充电器就叫做电源适配器,用在做转换,对电压进行相关的转换适配我们的设备。栈,队列不是自己直接管理数据,是让其他容器管理数据,在其他容器上去封装转换我想要的东西。
和容器 vector,list相比,他们是直接自己管理数据,但是栈不是
2.接口
2.1 stack
核心的接口是empty,size,top,push,pop
2.2 queue
核心的接口是empty,size,front,push,pop
3.使用
3.1 stack
void test_stack()
{
stack<int> st;
st.push(1);
st.push(2);
st.push(3);
st.push(4);
while (!st.empty())
{
cout << st.top() << " ";
st.pop();
}
cout << endl;
}
3.2 queue
void test_queue()
{
queue<int> q;
q.push(1);
q.push(2);
q.push(3);
q.push(4);
while (!q.empty())
{
cout << q.front() << " ";
q.pop();
}
cout << endl;
}
4. 应用
4.1 最小栈
利用双栈的思路,以空间换时间,<=都更新
class MinStack {
public:
MinStack() {
}
void push(int val) {
_st.push(val);
if(_minst.empty()||val<=_minst.top())
{
_minst.push(val);
}
}
void pop() {
if(_st.top()==_minst.top())
{
_minst.pop();
}
_st.pop();
}
int top() {
return _st.top();
}
int getMin() {
return _minst.top();
}
stack<int> _st;
stack<int> _minst;
};
但是要是st中是大量重复的数据,应该怎么办呢?
按照上面的代码,minst必须全部进
minst中不要存数据,存个数 (5,1)(3,1)stack<countVal>_minst
struct countVal
{
int _val;
int _count=0;
}
4.2 栈的压入、弹出序列
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
思路:模拟出栈入栈顺序
步骤1:入栈序列先入栈,结束条件:入栈序列走到尾就结束!
匹配:栈为空
不匹配:栈不为空
步骤2:栈顶数据和出栈序列比较
a.如果匹配,出栈序列++,出栈顶元素,继续比较,直到栈为空或者不匹配
b.如果不匹配,入栈序列先入栈
class Solution {
public:
bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {
stack<int> st;
size_t pushi=0,popi=0;
while(pushi<pushV.size())
{
st.push(pushV[pushi++]);
while(!st.empty()&&st.top()==popV[popi])
{
st.pop();
popi++;
}
}
return st.empty();
}
};
4.3 二叉树的分层遍历(用队列)
给你二叉树的根节点 root
,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
输入:root = [3,9,20,null,null,15,7] 输出:[[3],[9,20],[15,7]]
思路1:双队列
思路2:用一个levelSize和一个队列
思路2的实现
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> q;
int levelSize=0;
if(root)//队列不为空
{
q.push(root);
levelSize=1;
}
vector<vector<int>> vv;
while(!q.empty())
{
vector<int> v;
while(levelSize--)//控制了一层一层出
{
TreeNode* front=q.front();
q.pop();
v.push_back(front->val);//放的不是节点的指针,只需要val
if(front->left)
q.push(front->left);
if(front->right)
q.push(front->right);
}
vv.push_back(v);//下一层已经全部进入队列
levelSize=q.size();//更新levelSize,队列中的数据个数就是下一层的数据个数
}
return vv;
}
};
4.4 逆波兰表达式求值
给你一个字符串数组
tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。请你计算该表达式。返回一个表示表达式值的整数。
输入:tokens = ["2","1","+","3","*"] 输出:9 解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
//首先判断是操作数还是操作符
for(auto& str:tokens)
{
if(str=="+"
||str=="-"
||str=="*"
||str=="/")
{
//如果是操作符
int right=st.top();
st.pop();
int left=st.top();
st.pop();
switch(str[0])
{
case '+':
st.push(left+right);
break;
case '-':
st.push(left-right);
break;
case '*':
st.push(left*right);
break;
case '/':
st.push(left/right);
break;
}
}
else
{
//操作数入栈
st.push(stoi(str));
}
}
return st.top();
}
};
扩充中缀转后缀(不是很重要)
遇到括号:递归子问题解决