C++STL的stack和queue(超详解)
文章目录
- 前言
- stack
- 栈的题目
- 最小栈
- JZ31 栈的压入、弹出序列
- 150. 逆波兰表达式求值
- stack的模拟实现
- queue的模拟实现
- deque
- deque底层设计
前言
栈和队列这一块其实有数据结构的基础,学起来非常简单。
stack
栈的成员函数就这么写,除了emplace其他都已经非常熟悉了。
stack没有迭代器吗?
没有,因为栈已经不是容器了,它是容器适配器。给它一个迭代器还能保证先进先出这些吗?不能。
stack跟我们之前学的list其实很不太一样。
模板参数不同。
先快速用一下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;
}
栈的题目
最小栈
接下来我们做题来加深一下对stack的理解。
最小栈
思路
首先定义两个栈,一个栈是正常的栈,实现正常的操作。
我们用另一个栈是最小栈,来实现O(1)检索到最小元素的栈。
这里要不要写那4个默认成员函数?
不用。
push
如果是空栈或者需要push的数据小于最小栈栈顶元素,我们就push.否则最小栈不做处理。
注意,如果需要push的数据等于栈顶元素也要push,否则pop的时候会把最小值也pop掉
pop
如果最小栈的栈顶元素和正常栈的栈顶元素相等我们就pop
class MinStack {
public:
//不用写MinStack() {}void push(int val) {_st.push(val);if (_minst.empty() || val <= _minst.top()){_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;
};
优化
如果是这样那不是很浪费。
可以这样优化,每个地方不是存一个值而是存一个结构。
给大家看一下结构,具体实现就先不实现了。
stack<int> _st;
struct Data
{int _val;int _count;
}
stack<Date> _minst;
这就是模板的好处,如果没有模板,那自己还需要再写一个栈。
JZ31 栈的压入、弹出序列
栈的压入、弹出序列
这道题稍有不慎就会写的很复杂,如果想清楚了也挺简单的。
不匹配的一种情况
思路
这道题有很多种思路,最简单的就是用一个栈模拟入栈出栈的过程。
如果能模拟出来就匹配了,如果模拟不出来就不行。
所以我们的重点在于模拟这个栈。
先要第一个出4,那就入数据1234。只要不匹配就入数据。
下一个出5,不匹配继续入
再看下一个要出的数据是不是栈顶的元素,是就直接出。
如果能把入栈序列走完,出栈序列也走完,那就匹配了。
以pushi为主要的,因为popi不一定能走到结尾。
第一步,入栈
第二步,判断是否要出栈(注意不一定只出一次)
凡是这样写一定要小心,栈出了一个,然后栈空了。
空栈调用会报错。
怎么样匹配?
两种方式
1.popi走到尾了
2.栈为空
150. 逆波兰表达式求值
逆波兰表达式求值
中缀表达式
我们平时写的式子都是中缀表达式。但是计算机对于中缀表达式没办法直接运算。
比如1+2*(3-2),计算机遇到操作数的时候是不敢运算的,因为还涉及到优先级。
后缀表达式
所以我们先把优先级给确定出来。
后缀就是优先级已经按先后顺序确定了。
上面的这道题就是用后缀表达式求出结果?省去了中缀转后缀的过程,所以难度大大降低了。
运算后缀表达式
用一个栈就搞定了。
过程
操作数入栈
操作符计算
先出的是右操作数。计算,结果入栈。
最后
这道题不难,但是你要理解一个逆波兰表达式为什么可以这样算,你就要理解中缀怎么转后缀。
代码实现
怎么确定是操作数还是操作符?
这里有个小坑,如果操作不当,减号和负数会混。
最简单的方式是用一个字符串的比较就可以了
操作数入栈
操作符出栈,计算。
如何中缀转后缀?
注意,输出并不指的是打印,而是说把数据放到一个容器里保存起来。
跟栈顶操作符比较,优先级更高,不能直接输出,因为后面可能还有优先级更高的。
然后回到之前第一步,操作数输出
综上所述,我们便可以看到为什么后缀运算可以利用一个栈来进行模拟?
中缀转后缀的时候。
操作符出的时候,跟我相邻的两个数,就是要跟这个操作符的两个数运算,结果作为操作数又进行运算。
中缀转后缀就是这样转的,它的规则就是这样的。
操作符出了,我要让两个操作数一定是在我的前面。那我怎么找到最近的两个操作数呢?
栈的后进先出刚刚好
很巧很巧,像发明栈的大佬致敬。
真正麻烦处理的还是带括号的。
比如1 + 2*(4 - 5)+ 6/7;
可以尝试先把后缀表达式写出来。
flag的解决方式
flag0的时候正常处理。
flag1的时候说明遇到括号了。
下一个的运算符优先级是高。
不用flag的解决方式
这里就先不讲了。
stack的模拟实现
栈的实现有两种方式。
1.数组栈,尾部当作栈顶。
2.链表栈,头部当作栈顶。
数组栈更有优势一点。
传统的写法,无非就是搞一个数组,不够了就扩容。
我们这里用一个适配器的玩法。
适配器的本质是什么?
现实生活中,我们的充电头也叫电源适配器。电源适配器是干嘛的?是生产电源的吗?
其实是用来变压的。
所以适配器的本质是用来转换的,把原来的东西给转换过来。
容器适配器,它不是自己存储数据,它是把已有的东西进行转换。
我们要实现一个顺序栈,链表栈,我们需要自己写吗?
我们可以拿一个已有的容器封装,这样写起来更简单。
但是这还不是适配,还要转换。
再增加一个模板参数,Container,他具体是啥我也不知道,但是它肯定是符合我们要求的容器。
要实现顺序栈,传vector.
要实现链表栈,传list.
namespace but
{template<class T, class Container>class stack{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_back();}const T& top(){return _con.back();}size_t size(){return _con.size();}bool empty(){return _con.empty();}private://vector<T> _v;Container _con;};void test_stack(){stack<int, vector<int>> st;//顺序栈//stack<int, list<int>> st;//链式栈//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;}
}
还可以给缺省类型。
template<class T, class Container= vector<T>>
函数传参如果不从右往左会有歧义。
假设传两个参数,你就不知道传给谁了。
queue的模拟实现
快速手搓。
namespace but
{template<class T, class Container = list<T>>class queue{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_front();}const T& front(){return _con.front();}const T& back(){return _con.back();}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:Container _con;};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;}
}
队列还能不能用vector适配?
队列要头插尾删,vector不支持头删。如果强行用erase,效率有点低。
在实现队列的头文件里没有包括vector和list为什么还能用?
如果编译它是会报错的,但是编译器不编译它。.h是不会被编译的,它是在包含的地方展开,然后编译器向上找。
这样写就不行了
为什么?
因为c和c++编译的时候都有一个特点,他不会在整个文件里面找。一展开像上去找,找不到vector,因为vector在std里面,又没有指定std.
在命名空间里只有指定或者展开才能找到。
从string开始,只写.h,不写cpp,为什么?
从规范角度来说肯定要写的,模板不能这么写,这样写出来是有问题的。
你可以尝试用声明和定义分离写一下stack。
为什么又找不到vector?
stack.cpp这里展开.h,又找不到vector.
声明和定义分离会导致很多问题,他会导致链接错误。链接错误就是找不到定义。
模板不能声明和定义分离。
deque
栈的默认,默认容器用了一个deque的东西,这个东西是啥?
deque虽然是队列,但它不是正队列,它是双端队列。
deque对标的是vector+list.
它的结构和前面没有什么差别。
这些功能只有我们之前讲的list能做到。
最牛逼的是还有这个
看,它既支持vector的功能又支持list的功能。
但是这个东西真的这么牛吗?
要回答这个问题,我们得看一下deque的底层设计。
deque底层设计
我们先来分析一下顺序表和链表的区别。
顺序表:
它最大的优点就是空间连续随机访问,但是也带来了,头插,中间插入删除的困难。
其实顺序表还有一个优点就是高速缓存效率高,但是这里学习的时候不作为重点。
链表:
能不能把这两个合二为一呢?
相关文章:

C++STL的stack和queue(超详解)
文章目录 前言stack栈的题目最小栈JZ31 栈的压入、弹出序列150. 逆波兰表达式求值 stack的模拟实现queue的模拟实现dequedeque底层设计 前言 栈和队列这一块其实有数据结构的基础,学起来非常简单。 stack 栈的成员函数就这么写,除了emplace其他都已经非…...
【C语言实现windows环境下Socket编程TCP/IP协议】
C语言实现windows环境下Socket编程TCP/IP协议 主要是记录解决一些在我本地编译运行时出现的问题connect :No error关于头文件关于stray /xxx和socket:No error问题千万记得是服务器先启动哦,客户端后启动下面附上我改好的代码 主要是记录解决…...

CGAL的3D简单网格数据结构
由具有多个曲面面片的多面体曲面生成的多域四面体网格。将显示完整的三角剖分,包括属于或不属于网格复合体、曲面面片和特征边的单元。 1、网格复合体、 此软件包致力于三维单纯形网格数据结构的表示。 一个3D单纯形复杂体由点、线段、三角形、四面体及其相应的组合…...

正则表达式(9):扩展正则表达式
正则表达式(9):扩展正则表达式 小结 本博文转载自 前文中一直在说,在Linux中,正则表达式可以分为”基本正则表达式”和”扩展正则表达式”。 我们已经认识了”基本正则表达式”,现在,我们来认…...

静态SOCKS5:了解基本概念和协议
SOCKS5是一种网络协议,是SOCKS协议的第五个版本,它提供了一种安全的、加密的网络连接,可以帮助用户在互联网上保护自己的隐私和安全。静态SOCKS5是指使用静态IP地址和端口的SOCKS5代理服务器,这种代理服务器可以提供更稳定、更快速…...

用23种设计模式打造一个cocos creator的游戏框架----(十二)状态模式
1、模式标准 模式名称:状态模式 模式分类:行为型 模式意图:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。 结构图: 适用于: 1、一个对象的行为决定于它的状态,并且它必须…...

js 转换为数组并返回(Array.of())
Array提供了方法直接将一组值转换为数组并返回 Array.of()方法 Array.of(1,2,3) 结果...
git上传文件夹后打不开,有@.....
这种情况是你上传的这个文件夹也是个git仓库,需要删除.git文件。 如果你删除.git文件后,上传git还是不行,文件夹还是…,那就需要清理以下整个项目的缓存: git rm -r --cached ....

31、应急响应——Windows
文章目录 一、账户排查1.1 登录服务器的途径1.2 弱口令1.3 可疑账号 二、网络排查三、进程排查四、注册表排查五、内存分析 一、账户排查 1.1 登录服务器的途径 3389smb 445httpftp数据库中间件 1.2 弱口令 弱口令途径:3389、smb 445、http、ftp、数据库、中间件…...
QT linux下使用Qt Creator调试附加进程,加快调试
文章目录 一、调试附加进程二、配置流程(1)开放linux内核配置项(2)命令行直接启动程序(3)调试附加到进程 一、调试附加进程 使用附加进程调试要比直接调试速度要快,但是不足之处是,…...

IDEA Maven项目如何引用本地jar包,并打包发布
jar包位于当前路径下的lib目录中 引入所需要的配置 查看当前jar包的相关信息 包的引入,需要使用到当前包的artifactId, groupId, version 需要到包的/META-INF/maven/ 下面的 pom.xml 文件里面找 在Maven构建项目时,生成的依赖包中的/META-INF/maven目录存放了一些…...

Unity中Batching优化的GPU实例化(3)
文章目录 前言一、UNITY_SETUP_INSTANCE_ID(v);二、在UnityInstancing.cginc文件中,看一下Unity这句话做了什么1、使用了该 .cginc 后,会自动预定义该函数2、需要满足GPU实例化条件,才会执行对应语句3、满足GPU实例化后,主要执行的…...

Web应用JSON数据保护(密码算法、密钥、数字签名和数据加密)
1.JSON(JavaScript Object Notation) JSON是一种轻量级的数据交换格式,采用完全独立于编程语言的文本格式来存储和表示数据。JSON通过简单的key-value键值对来描述数据,可以被广泛用于网络通信、数据存储等各种应用场景࿰…...

【软件安装】VMware安装Centos7虚拟机并且设置静态IP,实现Windows和Centos7网络互相访问
这篇文章,主要介绍VMware安装Centos7虚拟机并且设置静态IP,实现Windows和Centos7网络互相访问。 目录 一、VMware安装Centos7 1.1、下载Centos7镜像 1.2、安装Centos7系统 二、设置静态IP地址 2.1、查看虚拟机网络IP 2.2、禁用NetworkManager服务 …...
203. 移除链表元素
203. 移除链表元素 https://leetcode.cn/problems/remove-linked-list-elements/description/ 方法一:迭代 迭代遍历链表 注意:这里的head是指向第一个节点的(首元节点),并没有一个虚拟的头节点,所以这…...

最新鸿蒙HarmonyOS4.0开发登陆的界面1
下载deveco-studio 说明一下,本人只是学习中,现在只是拿着vue及uniapp的经验在一点一点的折腾,不过现在看来,鸿蒙入门并不是很难。也许是自己没有深入下去。 https://developer.harmonyos.com/cn/develop/deveco-studio#download…...
【模型训练】目标跟踪
【模型训练】目标跟踪...

zabbix——实现高效网络监控
在当今的数字化时代,网络和服务器的健康状况对于企业的正常运营至关重要。为了及时发现和解决潜在的问题,许多企业选择使用网络监控工具来追踪服务器的性能和网络参数。其中,Zabbix是一个功能强大且开源的网络监控工具,被广泛应用…...

LeetCode力扣每日一题(Java):58、最后一个单词的长度
一、题目 二、解题思路 1、我的思路 先将字符串转换成字符数组 由于我们需要获取最后一个单词的长度,所以我们从后往前遍历字符数组 我们还需判断所遍历的字符是不是字母,即判断每个字符对应的ASCII值即可,用计数器count来储存单词长度 …...
一、python requests爬虫[基础、上传文件、会话维持、代理设置]
一、requests 1. 发送 解释:向服务器发送请求 1.1 请求页面方式 requests.get(www.baidu.com) requests.post(www.baidu.com) 1.2请求参数 1.2.1 get params {"id":16,"name":"jack" } requests.get(www.baidu.com,paramspara…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...

Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
在树莓派上添加音频输入设备的几种方法
在树莓派上添加音频输入设备可以通过以下步骤完成,具体方法取决于设备类型(如USB麦克风、3.5mm接口麦克风或HDMI音频输入)。以下是详细指南: 1. 连接音频输入设备 USB麦克风/声卡:直接插入树莓派的USB接口。3.5mm麦克…...
深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向
在人工智能技术呈指数级发展的当下,大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性,吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型,成为释放其巨大潜力的关键所在&…...

stm32wle5 lpuart DMA数据不接收
配置波特率9600时,需要使用外部低速晶振...
智能职业发展系统:AI驱动的职业规划平台技术解析
智能职业发展系统:AI驱动的职业规划平台技术解析 引言:数字时代的职业革命 在当今瞬息万变的就业市场中,传统的职业规划方法已无法满足个人和企业的需求。据统计,全球每年有超过2亿人面临职业转型困境,而企业也因此遭…...

WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...