C++-stack 和 queue

news2024/12/23 22:06:41

 stack 和 queue介绍

 两者分别是C++当中的 栈和队列,只不过在C++当中,这两者没有用传统的方式,比如顺序存储和链式存储来实现了,两者现在使用的是一种权限的方式来实现;

都是用容器适配器来实现,开发者考虑到,没有必要在像传统写法一样去实现,直接复用容器来实现即可,如下图官方文档所示,两者都是基于 deque 这个容器来实现的:

 而适配器的本质其实就是复用

 两者实现的功能其实和我们在数据结构当中学习的没有什么区别,结构也是一样的;

 两者都是容器适配器,不支持我们随便的去遍历,都是有自己的插入删除的规则的,所以这两个容器不支持迭代器。

 stack官方文档:stack - C++ Reference (cplusplus.com)

 queue官方文档:queue - C++ Reference (cplusplus.com)

stack 和 queue 的 例题

 因为 STL 当中的类使用起来都是类似的,而两者的使用非常的简单,所以直接用几个例题来了解 stack 和 queue两个类的使用。

155. 最小栈 - 力扣(LeetCode)

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。

 问题就在于, geiMin()这个函数,而且要求在 O(1)的时间复杂度。所以不能用常规方式来解决,而且栈也是不支持遍历的。

首先我们想到的是,在MinStack类当中有一个栈容器,有一个Min成员,用于存储栈容器当中的最小值,当push一个比Min小的值就更新Min。这样做有一个很多的问题,当需要Pop的时候,很难及时更新Min。

所以上述方式不可行。

解决这个问题,我们使用两个栈来以空间换时间。一个栈是存储push进去的元素的,也就是存储数据的栈;另一个栈是存储第一个栈的最小值的,只不过存储方式有些许不同:

 如上图所示,_st 栈就是存储数据的栈,上述的例子push的顺序是 (3 4 5 1)。当_st  入栈 3 时候,此时 3 就是 _st 栈的最小值,那么在 _minst 当中就 push 3;然后 _st 当中 push 4 的时候,此时 _st栈 的最小值还是3,那么 _minst 栈还是 push 3,;接下里的5 也是一样的;当 _st 入栈 1的时候,1变成了 _st 栈的最小值,那么 _minst 栈就push  1。

用上面这样方式来记录没有push进去 _st 栈当中的时候,此时_st栈 当中的最小值是多少。

上述代码还可以进行优化,上述的_minst栈当中存储了多个3,其实这些重复的值是不用删的,只需要入栈更小的元素即可。如下图所示:

注意:上述优化的版本,如果 _st 当中入栈的元素和 _minst 栈顶元素相等的话,也是要入栈的。

可以不写构造函数,写上空的构造函数也是可以的,因为如果这个构造函数实现之后,就算其中没有任何操作,编译器也会去调用初始化列表,而初始化列表默认是,对内置类型不处理,对于自定义类型会去调用这个自定义类型的构造函数。所以,这个构造函数不写,可以;写上一个没有任何操作的空的构造函数也是可以的。

同样析构函数也是没有必要的写的,这里编译器会自动生成,来对 minstack这个类进行处理,而其中的两个栈成员,stack有自己的析构函数来处理,所以在这个类当中,析构函数是不用写的。

代码实现:

class MinStack {
public:
    // 可写可不写
    MinStack() {
    }
    
    void push(int val) {
        _st.push(val);

        if(_minst.empty() || _minst.top() >= val)
        {
            _minst.push(val);
        }
    }
    
    void pop() {
        if(_minst.top() == _st.top())
        {
            _minst.pop();
        }

        _st.pop();
    }
    
    int top() {
        return _st.top();
    }
    
    int getMin() {
        return _minst.top();
    }

private:
    stack<int> _st;
    stack<int> _minst;
};

 栈的压入、弹出序列_牛客题霸_牛客网 (nowcoder.com)

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。

1. 0<=pushV.length == popV.length <=1000

2. -1000<=pushV[i]<=1000

3. pushV 的所有数字均不相同

 判断压入和弹出顺序是否相同,可以进行模拟实现。如下例子分析: 

首先这哥例子是满足条件的,那么先从出栈顺序第一个开始判断,逐渐入栈。1 和 3 不相等,那么接着进行入栈,2 和 3 不相等,继续入栈, 3 和 3 相等,入栈3 之后出栈,然后 判断出栈顺序的 2 ,2 和 2 相等,继续出栈;接着,判断出栈顺序的5, 5 和 4 不相等,继续入栈;入栈顺序当中的5 入栈之后 和 出栈顺序当中5 相等,就出栈;接着 4 和 4 相等就出栈,最后入栈和出栈都完毕了。

如果是不满足条件的例子,按照上述的过程,当入栈完毕之后,出栈肯定没完毕,这时候说明不满足条件。

代码实现:

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pushV int整型vector 
     * @param popV int整型vector 
     * @return bool布尔型
     */
    bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {
        stack<int> st;
        int pushi = 0, popi = 0;

        while(pushi < pushV.size())
        {
            st.push(pushV[pushi++]);

            if(st.top() != popV[popi])
            {
                continue;
            }
            else 
            {
                while(!st.empty() && st.top() == popV[popi])
                {
                    st.pop();
                    ++popi;
                }
            }
        }

        return st.empty();
    }
};

150. 逆波兰表达式求值 - 力扣(LeetCode) 

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

 我们平常使用的表达式都是中缀表达式,如: 1 + 2 * 3 这样的表达式,中缀表达式就是 操作符在操作数的中间,但是这样不利于计算机识别优先级,计算机识别都是使用的后缀表达式,也就是上面所说的 逆波兰表达式。

他是 操作数的顺序不变,操作符的顺序按照优先级来排列,操作数在前,操作符在后,如:2 + 1 * 3 ,写成后缀表达式就是 2 1 3 * +  

上述题目要求只是把给定的后缀表达式 计算出结果,没有要求中缀转后缀,那么只是计算后缀表达式的结果就很简单了。

可以用一个栈来存储结果。首先让所有的操作数入栈,然后再取栈顶的两个元素进行运算,结果入栈。这样就可以计算出后缀表达式的结果。

代码实现:

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> st;
        for(auto& ch : tokens)
        {
            if(ch == "+" || ch == "-" || ch == "*" || ch == "/")
            {
                int right = st.top();
                st.pop();

                int left = st.top();
                st.pop();

                switch(ch[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(ch));
            }
        }

        return st.top();
    }
};

对于中缀转后缀,这里是简单的进行思路的解释:还是要用一个栈,一次遍历表达式,如果遇到操作数就直接输出,如果遇到操作符就入栈。

对于操作符入栈操作,有两大情况:

  • 栈为空 或者 当前操作符比栈顶 优先级高,继续入栈。
  • 栈不为空 或者 当前操作符比栈顶的优先级低或者相等,则输出栈顶操作符

 那么这里就涉及到 运算符优先级的问题,这个问题如果用 map建立对应的映射关系可以解决。如果不用map,可以用 if else  或 switch来暴力实现。

102. 二叉树的层序遍历 - 力扣(LeetCode) 

 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

这个题目和普通的层序遍历不一样,他还需要把树每一层结点值都赋值在一个二维数组每一层当中,所以,我们不光要打印,还要判断出当前打印的结点是那一层的。

法一:可以用两个队列,一个队列用于层序遍历,入队和出队树结点;另一个对了存储当前入队的结点属于那一层的层数。如下图所示;

 上述的双队列虽然能实现,但是不是最优解。

更优的是使用 一个 levelsize 变量来控制输出每一层的结点:

具体做法是当我 如某一层第一个结点之前,先把这一层的结点个数计算出来,保存到 levelsize当中;然后当我们输出一个这一层的结点的一个结点,levelsize-- ,直到levelsize 减到 0,此时说明这一层的结点已经输出完了。图下图所示(为第三层的输出之前):

 

我们可以用这样的方式来控制每一层的输出,但是问题在于我们如何计算每一层当中个数呢?

其实,在入队和出队这样循环,直到树当中遍历完全,是一个循环走到底;那么其实在这一层循环当中可以再套一层循环,这一层循环用于输出这一层的结点,当内层循环走完的时候,就是当前层数的结点已经出队完毕,但是这一层的所有孩子已经全部入队,而且此时队列当中的结点全部是上一层父亲结点的给出的孩子结点,也就是说,此时队列当中存储所有结点就是下一层的所有结点。

因此,我们可以直接求出当前队列当中元素个数,赋值给levesize就行了。

代码实现:
 

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> vv;
        queue<TreeNode*> q;
        int levelsize = 0;

        if(root)
        {
            q.push(root);
            levelsize = 1;
        }

        while(!q.empty())
        {
            vector<int> v;
            for(int i = 0; i < levelsize;i++)
            {
                TreeNode* front = q.front();
                q.pop();
                v.push_back(front->val);

                if(front->left)
                {
                    q.push(front->left);
                }

                if(front->right)
                {
                    q.push(front->right);
                }
            }
            
            vv.push_back(v);
            levelsize = q.size();
        }

        return vv;
    }
};

102. 二叉树的层序遍历 - 力扣(LeetCode)

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

使用上述方法,然后把用于存储 vv vector 类 reserve一下就行了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/792524.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PyToch 深度学习 || 3. 卷积神经网络 | 3.1 深度学习中的卷积操作

深度学习中的卷积操作 文章目录 深度学习中的卷积操作1. 卷积2. 一维卷积2.1 使用nn.functional库中conv1d2.2 使用nn库中的Conv1d 3. 二维卷积3.1 nn.functional.conv2d3.2 nn.Conv2d 1. 卷积 加权求和是一种非常重要的运算&#xff0c;可以整合局部数字特征进而是提取局部信…

Linux CentOS监控系统的运行情况工具 - top/htop/glances/sar/nmon

在CentOS系统中&#xff0c;您可以使用以下工具来监控系统的运行情况&#xff1a; 1. top&#xff1a; top 是一个命令行工具&#xff0c;用于实时监控系统的进程、CPU、内存和负载情况。您可以使用以下命令来启动 top&#xff1a; top 输出 2. htop&#xff1a; htop 是一…

WSL 2 环境配置

WSL 2 环境配置 wsl2是windows内置的linux子系统&#xff0c;安装步骤如下&#xff1a; Win10 版本号为 2004&#xff08;内部版本19041或更高&#xff09;即可&#xff0c;如果低于此版本可使用 Windows 10 易升工具手动升级。下载 Windows 10 易升工具&#xff1a; https:…

DAY52:动态规划(十七)子序列问题:最长递增子序列+最长连续递增序列+最长重复子数组

文章目录 300.最长递增子序列&#xff08;注意初始化和结果取值&#xff09;思路DP数组含义递推公式初始化最开始的写法debug测试&#xff1a;解答错误debug测试2&#xff1a;result初始值 修改完整版总结 674.最长连续递增序列思路1&#xff1a;滑动窗口思路2&#xff1a;动态…

【Leetcode】54.螺旋矩阵

一、题目 1、题目描述 给你一个 m m m 行 n n n 列的矩阵 matrix,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 示例1: 输入:matrix =

安防监控视频汇聚EasyCVR修改录像计划等待时间较长,是什么原因?

安防监控视频EasyCVR视频融合汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发等。音视频流媒体视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视频录像、云存储、回放与检…

项目——负载均衡在线OJ

目录 项目介绍开发环境所用技术项目宏观结构编写思路1. 编写compile_server1.1 编译模块编写1.2 运行功能1.3compile_runner 编译与运行1.4 编写compile_server.cpp调用compile_run模块&#xff0c;形成网络服务 2. 编写基于MVC的oj_server2.1 oj_server.cpp的编写2.2 oj_model…

Unity进阶--对象池数据场景管理器笔记

文章目录 泛型单例类泛型单例类&#xff08;不带组件版&#xff09;对象池管理器数据管理器场景管理器 泛型单例类 using System.Collections; using System.Collections.Generic;public abstract class ManagersSingle<T> where T : new() {private static T instance;…

OSCP 学习:Kali Linux 基本命令

Bash 环境 环境变量 当我们开启新的bash时候&#xff0c;它会拥有自己的环境变量 我是这样理解 环境变量的&#xff1a; 每个程序都有自己运行的地址 我们用一个变量来储存它的地址 这个变量就叫环境变量 Kali 最常用的环境变量 就是 $PATH。这个我们可以用这个变量进行不正当…

selenium浏览器驱动下载

Chrome谷歌浏览器 下载地址&#xff1a;http://chromedriver.storage.googleapis.com/index.html 不同的Chrome的版本对应的chromedriver.exe 版本也不一样&#xff0c;下载时不要搞错了。 如果是最新的Chrome, 下载最新的chromedriver.exe 就可以了。 Firefox火狐浏览器 驱…

B073-封装工具类 服务模块(后台)

目录 拿当前登录人信息工具类服务模块业务分析表结构后端代码后台代码覆写删除-加详情一起删调整前端Data&#xff0c;handleAdd和编辑框覆写新增编辑按钮展示详情资源&#xff1a;多图上传和回显图片 拿当前登录人信息工具类 工具类准备&#xff1a;LoginContext: 登录上下文…

前端性能测试

目录 前言&#xff1a; 前端性能 1、优化 2、Lighthouse 使用 4、Lighthouse 报告参数的标准 5、更多产品 前言&#xff1a; 前端性能测试是一个广泛的领域&#xff0c;它旨在评估前端应用程序的性能和可靠性。前端性能测试需要使用各种测试工具和技术&#xff0c;包括浏…

功率信号源的基本工作原理、用途和应用方法

功率信号源是一种可以产生恒定或可变功率输出的测试设备。在电子实验中&#xff0c;功率信号源广泛应用于各种不同的应用&#xff0c;下面安泰电子就来介绍功率信号源的基本工作原理、用途和应用方法。 功率信号源的基本工作原理 功率信号源的基本工作原理是将电能转换成信号能…

【前端实习评审】对小说详情模块的产品原型有一定的自己理解

大家好&#xff0c;本篇文章分享一下【校招VIP】免费商业项目“推推”第一期书籍详情模块前端同学的文档作品。该同学来自中国科学院大学计算机技术专业。 本项目亮点难点&#xff1a;1 热门书籍在更新点的访问压力 2 书籍更新通知的及时性和有效性 3 书荒:同好推荐的可能性 4…

血压诊断米家智能血压计方案

智能血压计产品介绍: 智能血压计是一种基于蓝牙技术的便携式血压测量设备。它通过无线连接与智能手机或其他设备同步并联接到APP端&#xff08;米家&#xff09;&#xff0c;可以准确测量用户的血压数据&#xff0c;并通过手机应用程序进行记录和分析。 智能血压计产品结构: 智…

Win10的两个实用技巧系列之蓝屏代码大全及解决方案、更改应用优先级的技巧

Win10怎么设置程序优先级? Win10更改应用优先级的技巧 Win10怎么设置程序优先级&#xff1f;Win10系统中任务管理器想要设置优先级&#xff0c;该怎么设置呢&#xff1f;下面我们就来看看Win10更改应用优先级的技巧 有些Win10用户想要调整程序优先级&#xff0c;以确保某些…

Sentinel限流中间件

目录 介绍 Sentinel 的特征 Sentinel 的组成 实战使用 简单实例 配置本地控制台 使用可视化ui配置简单流控 配置异步任务限流 使用注解定义限流资源 SpringCloud整合Sentinel 简单整合 并发线程流控 关联模式 整合openFeign使用 介绍 随着微服务的流行&#xff0…

iOS私钥证书和证书profile文件的生成攻略

在使用uniapp打包ios app的时候&#xff0c;要求我们提供一个私钥证书和一个证书profile文件&#xff0c;私钥证书可以使用mac电脑的钥匙串访问程序来生成&#xff0c;也可以使用香蕉云编来生成。证书profile文件可以直接在苹果开发者中心生成。 有部分刚接触ios开发的同学们&…

Easy-Es笔记

一、Easy-ES概述 Easy-Es&#xff08;简称EE&#xff09;是一款ElasticSearch-ORM框架&#xff0c;在原生 RestHighLevelClient 的基础上&#xff0c;只做增强不做改变&#xff0c;为简化开发、提高效率而生。Easy-Es采用和MP一致的语法设计&#xff0c;能够显著降低ElasticSea…

各种拉格朗日函数

目录 一&#xff0c;拉格朗日函数 二&#xff0c;部分拉格朗日函数 三&#xff0c;增广拉格朗日函数 一&#xff0c;拉格朗日函数 以三元函数为例&#xff1a; 求f(x,y,z)的极值&#xff0c;s.t.g(x,y,z)0 拉格朗日函数L(x,y,z,a) f(x,y,z) a * g(x,y,z) 在极值点处一…