C++STL初阶(11):stack和queue的使用

栈和队列的先导知识在这里: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;
    }

 

  • 12
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值