41 stack类与queue类

目录

一、简介

(一)stack类

(二)queue类

二、使用与模拟实现

(一)stack类

1、使用

2、OJ题

(1)最小栈

(2)栈的弹出压入序列

(3)逆波兰表达式求值

3、模拟实现

(二)queue类

1、使用

2、模拟实现

三、priority_queue类

(一)使用

(二)OJ题

1、数组中第K个大的元素

(三)模拟实现

四、deque类(了解)

(一)原理介绍

(二)deque缺陷

(三)做底层默认容器


一、简介

(一)stack类

        在 C++ 中,stack(栈)类是一个容器适配器,它被定义在<stack>头文件中。容器适配器是一种设计模式(就是把解决问题的经验总结出来),它允许将一个已有的容器类(如 vector、list或deque)转换为另一种容器类型的接口stack的情况下,以其他类型的容器为基础,并与提供栈这种数据结构相关操作的接口进行封装。具体声明如下:

        类模板第一个参数是类型,第二个参数为适配器,默认为deque。

(二)queue类

        在 C++ 中,queue(队列)类也是一个容器适配器,它提供了队列这种数据结构的功能。它被定义在<queue>头文件中,像stack一样,queue也是基于其他底层容器(如dequelist)来实现的,默认底层容器是deque。具体声明如下:

        类模板第一个参数是类型,第二个参数为适配器,默认为deque。

二、使用与模拟实现

        stack类与queue类的接口比较简单,因为要保证数据的后进先出/先进先出的属性,所以不提供迭代器。(设计迭代器的话就可以遍历到栈中的每一个元素,就能进行随机插入与删除,就违反了后进先出/先进先出的理念)

(一)stack类

1、使用

        stack类本质是实现栈的功能,即具备先进后出的属性与相关接口,具体如下:

       

函数说明接口说明
stack()
构造空的栈
empty()
检测 stack 是否为空
size()
返回 stack 中元素的个数
top()
返回栈顶元素的引用
push()
将元素 val 压入 stack
pop()
stack 中尾部的元素弹出

        示例代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<stack>
#include<queue>
#include<vector>
using namespace std;void test01()
{stack<int, vector<int>> st;for (size_t i = 1; i < 5; i++){st.push(i);}cout << "empty():" << st.empty() << endl;cout << "size():" << st.size() << endl;//遍历cout << "遍历:" << endl;for (size_t i = 1; i < 5; i++){cout << st.top() << " ";st.pop();}cout << endl;
}int main()
{test01();return 0;
}

        结果如下:

        注意:栈的遍历只能是一边出一边看。

2、OJ题

(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();}private:stack<int> _st;stack<int> _minst;
};

(2)栈的弹出压入序列

        解题思路:

        ① 创建一个栈;

        ② 给入栈数组给一个指针pushi,先入栈pushi位置的数据,pushi++;

        ③ 给出栈数组给一个指针popi,栈顶数据跟popi位置序列数据比较,若果匹配则出栈,popi++,回到第二步;不匹配或栈为空则回到第一步。(不匹配是后面才出栈);

        ④ 到了最后,pushi等于pushV.size(),若全部匹配,则栈是空的,判空的结果与返回的结果一致;若不匹配则栈不为空。

        代码如下:

bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {size_t pushi = 0;size_t popi = 0;stack<int> st;while(pushV.size()>pushi){st.push(pushV[pushi++]);while(!st.empty() && popV[popi] == st.top()){st.pop();popi++;}}return st.empty();}

(3)逆波兰表达式求值

        解题思路:

        ① 操作数入栈;

        ② 操作符,取栈顶两个操作数运算,运算结果继续入栈;(先取出来的是右操作数,因为栈的先进后出原则)

        ③ 最后一个栈元素就是运算结果。

        代码如下:

class Solution {
public:int evalRPN(vector<string>& tokens) {stack<int> s;for(auto& str : tokens){if(!(str=="+" || str=="-" || str=="*" || str=="/")){//操作数则入栈s.push(stoi(str));}else{//操作符,取栈顶两元素进行运算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;}}}return s.top();}
};

        注意:

        ① 操作符是一个字符,从string里取出来的操作符在case中要用' '进行引用。

        ② 因为操作数可能是多位或者是负数,所以使用中括号加下标的形式进行使用操作数的话可能要把他们拼在一起,非常麻烦,所以直接使用stoi把string匿名对象的内容直接转为整形。

3、模拟实现

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
#include<deque>namespace zyb 
{template<class T, class Container = deque<T>>//半缺省模板参数class stack{public: //不用接构造函数,因为会调用其他结构的默认构造void push(const T& x){_con.push_back(x);}void pop(){_con.pop_back();}T& top(){return _con.back();}size_t size() const // 指向的内容不能修改{return _con.size();}bool empty() const{return _con.empty();}private:Container _con;//使用其他结构来作为栈的结构};
}

       测试代码如下:

void test01()
{zyb::stack<int> st;for (size_t i = 0; i < 5; i++){st.push(i);}cout << "size():" << st.size() << endl;cout << "top():" << st.top() << endl;cout << "empty():" << st.empty() << endl;while (!st.empty()){cout << st.top() << " ";st.pop();}
}

        结果如下所示:

        注意:把传入容器的尾部当做栈顶,对栈进行插入删除操作时直接push_back与pop_back即可,若要获取栈顶元素,使用back()这种通用型接口即可获得栈顶元素。

(二)queue类

1、使用

        queue类本质是实现队列的功能,即具备先进先出的属性与相关接口,具体如下:

        示例代码如下:

void test02()
{queue<int> q;for (size_t i = 1; i < 5; i++){q.push(i);}cout << "empty():" << q.empty() << endl;cout << "size():" << q.size() << endl;cout << "front():" << q.front() << endl;cout << "back():" << q.back() << endl;//遍历cout << "遍历:" << endl;for (size_t i = 1; i < 5; i++){cout << q.front() << " ";q.pop();}cout << endl;
}int main()
{test02();return 0;
}

        运行结果如下:

2、模拟实现

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<deque>namespace zyb
{template<class T, class Container = deque<T>>//半缺省模板参数class queue{public://不用接构造函数,因为会调用其他结构的默认构造void push(const T& x){_con.push_back(x);}void pop(){_con.pop_front();}T& front(){return _con.front();}T& back(){return _con.back();}size_t size() const // 指向的内容不能修改{return _con.size();}bool empty() const{return _con.empty();}private:Container _con;//使用其他结构来作为栈的结构};
}

       测试代码如下:

void test02()
{zyb::queue<int> q;for (size_t i = 0; i < 5; i++){q.push(i);}cout << "size():" << q.size() << endl;cout << "front():" << q.front() << endl;cout << "back():" << q.back() << endl;cout << "empty():" << q.empty() << endl;while (!q.empty()){cout << q.front() << " ";q.pop();}
}

        结果如下所示:

        注意:

        ① 队列不能使用vector进行适配,因为vector不支持头删。

        ② 在测试类中要先展开命名空间再引入stack或queue类模板(里面没展开命名空间std),因为头文件展开后找不到展开的命名空间std,deque找不到出处,会报错。(在vs中写在头文件下面也没事,因为头文件处只是一个类模板,没有实例化,在编译时只做简单的检测,在进行业务处理的时候进行实例化再检查,发现已有命名空间,所以不会报错)

三、priority_queue类

        在 C++ 中,priority_queue(优先队列,)类是一种特殊的队列容器适配器根据严格的弱排序标准(less),它的第一个元素总是它所包含的元素中最大的。

        类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素,默认大根堆)。具体声明如下:

(一)使用

        优先级队列默认使用vector作为其底层存储数据的容器在vector上又使用了堆算法将vector中元素构造成堆的结构因此priority_queue就是堆所有需要用到堆的位置,都可以考虑使用priority_queue。注意:默认情况下priority_queue是大堆。

函数声明
接口说明
priority_queue()
priority_queue(first, last)
构造一个空的优先级队列
empty( )
检测优先级队列是否为空,是返回 true ,否 则返回 false
top( )
返回优先级队列中最大 ( 最小元素 ) ,即堆顶元
push(x)
在优先级队列中插入元素 x
pop()
删除优先级队列中最大 ( 最小 ) 元素,即堆顶元

(二)OJ题

1、数组中第K个大的元素

        解题思路:根据优先队列的特性,pop出来的都是最大的元素,则可先pop前k-1个元素,最后再取top元素。

        代码如下:

class Solution {
public:int findKthLargest(vector<int>& nums, int k) {//建堆(默认大堆,出的也是大的数字)priority_queue<int> p(nums.begin(), nums.end());while(--k){p.pop();//把前k-1个最大的数删掉}return p.top();//在栈顶的就是最大的那个}
};

(三)模拟实现

#pragma once
#include<iostream>
#include<vector>namespace zyb
{template<class T, class Container = vector<T>>class priority_queue//小堆{public:void AdjustUp(int child){int parent = (child - 1) / 2;while (child > 0){if (_con[child] < _con[parent]){swap(_con[child], _con[parent]);child = parent;//更新下标parent = (parent - 1) / 2;}elsebreak;}}void push(const T& x)//插入一个数据后要使用向上调整算法佬保持堆的结构{_con.push_back(x);//尾插数据//进行向上调整算法AdjustUp(_con.size() - 1);}void AdjustDowm(int parent){int child = parent * 2 + 1;while (child < _con.size()){if (child + 1 < _con.size() && _con[child] > _con[child + 1])//孩子节点对比,选出较小的一个(因为是小根堆,父亲节点要小)child++;if (_con[parent] > _con[child])//交换父节点与孩子节点,移动节点位置{swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}elsebreak;}}void pop()//删除,先把堆顶元素与堆尾元素交换,删除堆尾元素,再进行向下调整算法{swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDowm(0);}bool empty(){return _con.empty();}const T& top(){return _con[0];}size_t size(){return _con.size(); }private:Container _con;};
}

        测试代码如下:

void test03()
{zyb::priority_queue<int> pq;//小堆for (size_t i = 0; i < 5; i++){pq.push(i);}cout << "size():" << pq.size() << endl;cout << "top():" << pq.top() << endl;cout << "empty():" << pq.empty() << endl;while (!pq.empty()){cout << pq.top() << " ";pq.pop(); }
}

        其结果为:

四、deque类(了解)

(一)原理介绍

        deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与 list比较,空间利用率比较高。

        deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,其底层结构如下图所示:

        双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在了deque的迭代器身上,因此deque的迭代器设计就比较复杂,如下图所示:

        那deque是如何借助其迭代器维护其假想连续的结构呢? 如下图所示:

(二)deque缺陷

        与vector比较,deque的优势是:头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此其效率比vector高的。

        与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段。

        但是,deque有一个致命缺陷:不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构时,大多数情况下优先考虑vector和list,deque的应用并不多,而目前能看到的一个应用就是,STL用其作为stack和queue的底层数据结构

(三)做底层默认容器

        stack是一种后进先出的特殊线性数据结构,因此只要具有push_back()和pop_back()操作的线性结构,都可以作为stack的底层容器,比如vector和list都可以;queue是先进先出的特殊线性数据结构,只要具有push_back和pop_front操作的线性结构,都可以作为queue的底层容器,比如 list。但是STL中对stack和queue默认选择deque作为其底层容器,主要是因为:

        ① stack和queue不需要遍历(stack和queue没有迭代器,避开了deque的缺点),只需要在固定的一端或者两端进行操作。

        ② 在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);queue中的 元素增长时,deque不仅效率高,而且内存使用率高。

        结合了deque的优点,而完美的避开了其缺陷。

 


        以上内容仅供分享,若有错误,请多指正。

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

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

相关文章

【笔记】深度学习模型评估指标

推荐链接&#xff1a; &#xff08;0&#xff09;多分类器的评价指标 &#xff08;1&#xff09;泛化误差的评价方法&#xff1a;【机器学习】模型评估与选择&#xff08;留出法、交叉验证法、查全率、查准率、偏差、方差&#xff09; &#xff08;2&#xff09;机器学习&…

Linux运维常见命令

vi/vim快捷键使用 1)拷贝当前行 yy ,拷贝当前行向下的5行 5yy&#xff0c;并粘贴&#xff08;输入p&#xff09;。 2)删除当前行 dd ,删除当前行向下的5行5dd 3)在文件中查找某个单词 [命令行下 /关键字&#xff0c;回车查找 ,输入n就是查找下一个 ] 4)设置文件的行号&…

评估大语言模型在药物基因组学问答任务中的表现:PGxQA

​这篇文献主要介绍了一个名为PGxQA的资源&#xff0c;用于评估大语言模型&#xff08;LLM&#xff09;在药物基因组学问答任务中的表现。 研究背景 药物基因组学&#xff08;Pharmacogenomics, PGx&#xff09;是精准医学中最有前景的领域之一&#xff0c;通过基因指导的治疗…

AI芯片常见概念

文章目录 AI芯片常见概念前言常见概念AI芯片分类按照芯片的技术架构分GPU半定制化的 FPGA全定制化 ASIC神经拟态芯片 按应用场景分训练卡推理卡 按部署位置分国产AI卡资料汇总 AI芯片算力和能效比AI芯片算力AI芯片能效比 封装相关Chiplet技术3DIC三星多芯片集成联盟&#xff08…

SpringBoot中使用AOP切面编程实现登录拦截

使用AOP切面编程实现登录拦截 1. 首先实现一个登录注册功能 以下代码仅供参考 控制层 RestController RequestMapping("/user") public class UserController {Autowiredprivate UserService userService;PostMapping("/register")public Result regis…

重温设计模式--享元模式

文章目录 享元模式&#xff08;Flyweight Pattern&#xff09;概述享元模式的结构C 代码示例1应用场景C示例代码2 享元模式&#xff08;Flyweight Pattern&#xff09;概述 定义&#xff1a; 运用共享技术有效地支持大量细粒度的对象。 享元模式是一种结构型设计模式&#xff0…

用python ollama qwen2.5 开发一个AI修仙游戏

用 Python Ollama (Qwen2.5) 开发一个 AI 修仙游戏 简介 本文将介绍如何使用 Python 和 Ollama (Qwen2.5 模型) 开发一个文字版修仙游戏。这个游戏具有以下特点&#xff1a; 完整的修仙世界观和成长体系基于 AI 生成的动态剧情和事件丰富的物品系统(功法、丹药、灵宝等)社交…

【网络安全】网站常见安全漏洞—服务端漏洞介绍

文章目录 网站常见安全漏洞—服务端漏洞介绍引言1. 第三方组件漏洞什么是第三方组件漏洞&#xff1f;如何防范&#xff1f; 2. SQL 注入什么是SQL注入&#xff1f;如何防范&#xff1f; 3. 命令执行漏洞什么是命令执行漏洞&#xff1f;如何防范&#xff1f; 4. 越权漏洞什么是越…

Linux驱动开发 IIC I2C驱动 编写APP访问EEPROM AT24C02

在嵌入式开发中&#xff0c;I2C&#xff08;Inter-Integrated Circuit&#xff09;是一种常用的串行通信协议&#xff0c;广泛应用于与外设&#xff08;如 EEPROM、传感器、显示屏等&#xff09;进行数据交换。AT24C02 是一种常见的 I2C EEPROM 存储器&#xff0c;它提供 2Kbit…

HDR视频技术之十一:HEVCH.265 的 HDR 编码方案

前文我们对 HEVC 的 HDR 编码优化技术做了介绍&#xff0c;侧重编码性能的提升。 本章主要阐述 HEVC 中 HDR/WCG 相关的整体编码方案&#xff0c; 包括不同应用场景下的 HEVC 扩展编码技术。 1 背景 HDR 信号一般意味着使用更多比特&#xff0c;一般的 HDR 信号倾向于使用 10…

linux普通用户使用sudo不需要输密码

1.root用户如果没有密码&#xff0c;先给root用户设置密码 sudo passwd root #设置密码 2.修改visudo配置 su #切换到root用户下 sudo visudo #修改visudo配置文件 用户名 ALL(ALL) NOPASSWD: ALL #下图所示处新增一行配置 用户名需要输入自己当前主机的用户名

【时间之外】IT人求职和创业应知【74】-运维机器人

目录 OpenAI最强推理模型o3发布&#xff0c;AGI测试能力暴涨 英伟达宣布收购以色列AI初创企业Runai 汤姆猫首款AI机器人产品明日发售 心勿贪&#xff0c;贵知足。 感谢所有打开这个页面的朋友。人生不如意&#xff0c;开越野车去撒野&#xff0c;会害了自己&#xff0c;不如…

C#调用WebService的方法

一、前言 在日常工作中&#xff0c;如果涉及到与第三方进行接口对接&#xff0c;有的会使用WebService的方式&#xff0c;这篇文章主要讲解在.NET Framework中如何调用WebService。 1.创建WebService &#xff08;1&#xff09;新建项目——模板选择ASP.NET Web 应用程序 &a…

Qt creator ,语言家功能缺失解决方法

1、找到工具->外部->配置 2、添加目录&#xff0c;双击命名语言家 3、在语言家目录下&#xff0c;添加工具 双击重命名lupdate&#xff0c;即更新翻译 %{CurrentDocument:Project:QT_INSTALL_BINS}\lupdate%{CurrentDocument:Project:FilePath}%{CurrentDocument:Projec…

Taro小程序开发性能优化实践

我们团队在利用Taro进行秒送频道小程序的同时&#xff0c;一直在探索性能优化的最佳实践。随着需求的不断迭代&#xff0c;项目中的性能问题难免日积月累&#xff0c;逐渐暴露出来影响用户体验。适逢双十一大促&#xff0c;我们趁着这个机会统一进行了Taro性能优化实践&#xf…

springboot471基于协同过滤算法商品推荐系统(论文+源码)_kaic

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装协同过滤算法商品推荐系统软件来发挥其高效地信息处理的作用…

进程间关系与守护进程

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 进程间关系与守护进程 收录于专栏[Linux学习] 本专栏旨在分享学习Linux的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. 进程组 什…

【NLP 16、实践 ③ 找出特定字符在字符串中的位置】

看着父亲苍老的白发和渐渐老态的面容 希望时间再慢一些 —— 24.12.19 一、定义模型 1.初始化模型 ① 初始化父类 super(TorchModel, self).__init__()&#xff1a; 调用父类 nn.Module 的初始化方法&#xff0c;确保模型能够正确初始化。 ② 创建嵌入层 self.embedding n…

javaEE-多线程编程-3

目录 java 常见的包 : 回调函数: 什么是线程: 第一个线程: 验证多线程执行: 内核: 调用sleep()方法: 执行结果分析: 线程创建的几种方式: 1.继承Thread类,重写run()方法. 2.实现Runnable接口,重写run()方法. 3.继承Thread类,重写run()方法.但使用匿名内部类 4.实现…

怎么在idea中创建springboot项目

最近想系统学习下springboot&#xff0c;尝试一下全栈路线 从零开始&#xff0c;下面将叙述下如何创建项目 环境 首先确保自己环境没问题 jdkMavenidea 创建springboot项目 1.打开idea&#xff0c;选择file->New->Project 2.选择Spring Initializr->设置JDK->…