栈和队列的先导知识在这里:C语言基础数据结构——栈和队列_栈和队列 插入取出数据-CSDN博客
1.容器适配器
从栈和队列开始,不少教材就不叫他们容器了,而是叫容器适配器
栈不是一种完全不同的数据结构,而是基于顺序表或者链表而实现的。
“stacks are a type of container adaptor”
栈和队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,stack和 queue都 提供了一组特定的成员函数来访问其元素。
Last In First Out:最后一个入栈的第一个出去
2. stack的工作原理以及使用
练手:最小栈
155. 最小栈 - 力扣(LeetCode)
思路一,利用双栈,第一个栈正常出入数据,第二个栈记录当前数据下的最小数据。
比如左栈先进12,此时最小的就是12,那么右栈就进12;同理4;当左栈进56时,右栈依然是栈顶存有最小数据4,所以再进一个4即可。
改进:以上方法虽然没错,但是会重复进很多个相同的元素,是否可以只进一次相同的元素呢?
我们给存放小数的那个栈叫“小栈”
只有当新入的元素比当前小栈的栈顶更小的时候我们才会继续入栈。
先不看两边栈顶的1,左栈是12 4 56 1 35 小栈就应该是12 4 1。
此时出栈的逻辑就会复杂一点,当左栈的元素大于小栈时,只出左栈即可,右栈不动就行。
当左栈即将出栈的元素大小和小栈的栈顶元素大小一样的时候,左栈和小栈同时出栈。
接着再来看红箭头指的1和左栈最上面的1:换句话说,当入栈的元素和最小值是一样的时候,是否在小栈里面也应该再入一个1呢?
答案是需要的:每当进入一个 小于等于当前小栈的栈顶元素时,都需要在小栈上加上压入的元素
再看个例子
删了需要更新。
使用双栈解决
只有当更小的值进入时才把更小的放入minst里去
出现与当前最小值相等的也需要进
函数名的push和_st.push()中的push不是同一个,后面是库中的push,第一个是我们自己实现的push
class MinStack {
public:
MinStack() {
}
void push(int val) {
st.push(val);
if(minst.empty()){
minst.push(val);
}else if(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();
}
private:
stack<int> st;
stack<int> minst;
};
压栈入栈序列问题
栈的压入、弹出序列_牛客题霸_牛客网 (nowcoder.com)
我们依然借助新建立一个栈来实现这个功能:
将push中的数据一个一个压入,每当压入的数据和出栈数据一样时就进行比较。
bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {
stack<int> st;
size_t i = 0,j = 0 ;
for( ; i < pushV.size() ; ++i){
st.push(pushV[i]);
while(j<popV.size() && st.top() == popV[j]){
j++;
st.pop();
if (st.empty()) break;
}
}
while(j<popV.size() && st.top() == popV[j]){
j++;
st.pop();
}
if(st.empty()) return true;
return false;
}
在使用中我们发现,stack的top不会检查是否为空,也不会在栈为空时有特殊的返回值:一旦对空栈进行top,会直接出现运行错误。
3.队列
队列是一种容器适配器,专门用于在 FIFO 上下文 ( 先进先出 ) 中操作,其中从容器一端插入元素,另一端提取元素。底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作 :empty :检测队列是否为空size :返回队列中有效元素的个数front :返回队头元素的引用back :返回队尾元素的引用push_back :在队列尾部入队列pop_front :在队列头部出队列不同于 栈的是:队列的底层多是使用deque
使用队列来回忆队列:
102. 二叉树的层序遍历 - 力扣(LeetCode)
复习一下C语言部分我们对二叉树的学习内容:
抛开此题的具体要求,二叉树的层序遍历是相对简单的事情:
一层带下一层即可。先入3,要出3的时候入3的左节点(若左节点存在),再入右节点(若右节点存在)。再当9要出的时候,入9的左右节点,但此处9是叶子,就不再入了。然后出20,再入20的左右节点。
如下图:
问题在于,此题要返回二维数组(vector的vector),那么如何在非满二叉树情况下一层一层的输入到vector就成了问题。
思路一:
使用两个队列。
另外一个队列来记录当前的数据属于第几排
思路二
使用一个变量levelSize而非队列来控制一层一层出:(本质和思路一差不多,思路一相当于是给每一个数据做记号,记录该结点是哪一层的,思路二则是使用一个数据整体记录。)
如何计数一层有多少个数呢?
每一层都会在上一层全部出完时完全进入队列,此时队列的size()就表示该层的数据个数
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> vv;
if (root==nullptr) return vv;
queue<TreeNode*> q;
q.push(root);
int LevelSize = 1; //根节点一定只有一个
while(!q.empty()){
vector<int> v;
while(LevelSize--){
TreeNode* front = q.front();
q.pop();
if(front->left) q.push(front->left);
if(front->right) q.push(front->right);
v.push_back(front->val);
}
vv.push_back(v);
LevelSize = q.size();
}
return vv;
}