C++stack和queue模拟实现以及deque的介绍

stack和queue介绍以及模拟实现

  • 1.stack
    • 1.1stack的介绍
    • 1.2stack的使用
  • 2.queue
    • 2.1queue的介绍
    • 2.2queue的使用
  • 3.容器适配器
    • 3.1什么是适配器
  • 4.stack模拟实现
  • 5.queue的模拟实现
  • 6.deque(双端队列)

1.stack

1.1stack的介绍

stack的文档介绍

  1. stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,只能从容器的一端进行元素的插入与提取操作。
  2. stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。
  3. stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以下操作:
    empty:判空操作
    back:获取尾部元素操作
    push_back:尾部插入元素操作
    pop_back:尾部删除元素操作
  4. 标准容器vector、deque、list均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器,默认情况下使用deque。

1.2stack的使用

stack的接口现在看起来对于前面已经学过string,vector,list已经是很简单的了。
在这里插入图片描述
这里就不再对接口进行详细介绍。来写几道题对stack的接口有更熟悉的使用。

最小栈
在这里插入图片描述

思路一
这道题大部分人的思路,可能是这样的,再申请一个变量,每次都和插入的数据进行比较,如果比新插入的数据小就更新。

在这里插入图片描述

思路二
申请两个栈,其中一个栈记录,插入最小的元素。

在这里插入图片描述
在这里插入图片描述
会初始化的,那为什么会初始化呢?
这个成员变量会走初始化列表,对内置类型不处理,对自定义类型调用它的构造函数。
那如果把这个Minstack()删掉,成员变量会不会初始化?
同样也是会的,系统默认生成的构造函数,对内置类型不处理,除非给内置类型缺省值,对自定义类型调用它的构造函数。

因此这里也没有析构函数。

class MinStack {
public:MinStack() {}void push(int val) {_min.push(val);//这里必须判空在前面,否则_count.top()会报错if(_count.empty() || _count.top() >= _min.top())_count.push(val);}void pop() {if(_count.top() == _min.top())_count.pop();_min.pop();}int top() {return _min.top();}int getMin() {return _count.top();}stack<int> _min;stack<int> _count;
};

JZ31 栈的压入、弹出序列

在这里插入图片描述

思路
这道题穷举是不可能的,
其实可以这样想,第一个是入栈序列,第二个是出栈序列,如果第一个的出栈序列可以和第二个出栈序列互相匹配,那不就是true了吗,不能匹配,return false;

在这里插入图片描述
这里就不再演示不匹配了,

写法1,返回条件以push1,pop1来进行判断。

class Solution {
public:bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {stack<int> _st;int i=0,j=0;_st.push(pushV[i++]);while(1){//相等就出栈if(!_st.empty() && _st.top() == popV[j]){_st.pop();++j;if(j == popV.size())return true;}//不相等/栈为空就入栈else {if(i == pushV.size() && j != popV.size() )return false;_st.push(pushV[i++]);}}}
};

写法2,返回条件以循环结构,st栈是否为空来判断

class Solution {
public:bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {stack<int> _st;size_t pop1=0;for(size_t push1=0;push1<pushV.size();++push1){_st.push(pushV[push1]);while(!_st.empty() &&_st.top() == popV[pop1]){_st.pop();++pop1;}}return _st.empty();}
};         

150. 逆波兰表达式求值

在这里插入图片描述

逆波兰表达式,就在后缀表达式。

在这里插入图片描述

后缀转中缀思路
遇见操作数直接入栈,遇到运算符"+“,”-“,”*“,”/“,出栈,先出的是右操作数,这是因为”-“,”/",要分左右。然后把结果入栈。最后栈中剩下的元素就是最终结果。

class Solution {
public:int evalRPN(vector<string>& tokens) {stack<int> _st;for(auto& str : tokens){if(str == "+" || str == "-" || str == "*" || str == "/"){int right=_st.top();_st.pop();int left=_st.top();_st.pop();switch(str[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;default:break;}}else{//字符串转为int,stoi函数_st.push(stoi(str));}}return _st.top();}
};

这里介绍一下C++把字符串变成各种类型的接口;
在这里插入图片描述

前面是把后缀变成中缀,这里再提供把中缀变成后缀的思路。
在这里插入图片描述

申请一个存放运算符的栈
1.操作数直接输出
2.栈空时,碰见运算符直接入栈,栈不空时,碰见运算符,需要外面运算符和栈顶的运算符比较。如果栈里面运算符优先级比外面的高或者相等,就一直出栈,直到栈空或者碰见优先级低于外面的运算符就停止。这个时候再把外面的运算符入栈。当遍历完之后,再把栈里面所有运算符依次出栈。

这个有兴趣可以写一下。
232. 用栈实现队列

提示:用两个栈。一个入栈,一个出栈。

2.queue

2.1queue的介绍

queue的文档介绍

  1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。
  2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。
  3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:
    empty:检测队列是否为空
    size:返回队列中有效元素的个数
    front:返回队头元素的引用
    back:返回队尾元素的引用
    push_back:在队列尾部入队列
    pop_front:在队列头部出队列
  4. 标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque。

2.2queue的使用

在这里插入图片描述
关于队列的题这里就不再讲解。
有兴趣可以写下面这道题
225. 用队列实现栈

提示:用两个队列。

3.容器适配器

3.1什么是适配器

适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口

其实到目前为止,我们已经接触了两种设计模式:
1.适配器模式
把已有的东西封装起来,转换出你想要的东西。
2.迭代器模式
不暴露底层实现细节,封装后提供统一的方式访问容器。

如果我们还是按照以往的想法,实现一个栈(如果是顺序栈),肯定是申请一个变长数组,一个size,一个capacity,再写一些成员函数。

template<class T>
class stack
{
public://成员函数
private:T* _a;size_t _size;size_t _capacity;
};

但是stack,queue都是适配器模式,我们可以不再自己写,而是可以用已有的东西封装起来,转换成自己想要的东西。

在这里插入图片描述

4.stack模拟实现

既然stack即可以用vector/list封装,因此模板我们给两个参数
在这里插入图片描述

#include<iostream>
#include<vector>
#include<list>
using namespace std;namespace bit
{template<class T,class container>class stack{public://自定义类型也可以不写构造stack() {};void push(const T& val){_con.push_back(val);}void pop(){_con.pop_back();}const T& top(){return _con.back();}bool empty(){return _con.empty();}size_t size(){return _con.size();}private:container _con;};
}

在这里插入图片描述

发现stack的模拟实现就是这么简单。。。

stack用list封装也是没有问题。

在这里插入图片描述

有人可能会说不对啊,我自己使用的stack可没有你传参这么麻烦

在这里插入图片描述

这里解决方法给第二个容器参数一个缺省值就行了。

在这里插入图片描述

在这里插入图片描述

5.queue的模拟实现

namespace bit
{template<class T,class container=list<T>>class queue{public:queue() {};void push(const T& val){_con.push_back(val);}void pop(){_con.pop_front();}const T& front(){return _con.front();}const T& back(){return _con.back();}bool empty(){return _con.empty();}size_t size(){return _con.size();}private:container _con;};
}

在这里插入图片描述

6.deque(双端队列)

deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。
在这里插入图片描述
但是deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组。

可能有人看了官方库发现,我们这里和库里面使用的容器不一样。
在这里插入图片描述
为什么库里面用的是deque(双端队列)

这里就不得不提到vector,list的缺点了
在这里插入图片描述

deque兼容了vector和list的优点
在这里插入图片描述
看起来deque这么好,那我们就只学这一种容器不就好了,还要学vector和list干吗,但是到现在我们还是在学vector和list,从这一方面就证明了,deque并不是那么完美。

deque底层结构
deque底层是由多个buffer数组,以及一个中控(指针数组)所组成。
在这里插入图片描述
deque这样的底层,才会即支持下标随机访问,又支持尾插尾删头插头删。

deque的缺点:

1.下标随机访问。
要算下标在第几个buffer,在这个buffer种第几个位置,因此下标随机访问有一定的时间消耗,不如vector快。

2.中间插入和删除。
也有一定的时间消耗,相比list中间插入删除不够极致,没有list快。

虽然deque有这些缺点,但是队友栈和队列是够用了。

那什么地方可以用deque(双端队列)呢?

中间插入和删除少,头尾插入删除多,偶尔下标随机访问。

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

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

相关文章

SBD(Schottky Barrier Diode)与JBS(Junction Barrier Schottky)

SBD和JBS二极管都是功率二极管&#xff0c;具有单向导电性&#xff0c;在电路中主要用于整流、箝位、续流等应用。两者的主要区别在于结构和性能。 结构 SBD是肖特基二极管的简称&#xff0c;其结构由一个金属和一个半导体形成的金属-半导体结构成。 JBS是结势垒肖特基二极…

xml文件报错 ORA-00907: 缺失右括号

原来的sql 更改之后 加一个select * from &#xff08;&#xff09;

测试用例基础

测试用例的基本要素 测试环境, 操作步骤, 测试数据, 预期结果 测试用例的设计方法 基于需求的设计方法 需求文档 -> 梳理需求(掌握需求) -> 针对文档设计测试用例 只是针对需求进行大概的测试 具体的设计方法 等价类 等价类: 依据需求将输入&#xff08;特殊情况…

Redis的java客户端

一、各种客户端的比较。 二、Jedis。 1.基本用法。 Jedis连接池。 这样&#xff0c;在建立连接的时候就只需要调用方法&#xff0c;如下所示 而close的底层本身也有对连接池的处理 三、SpringDataRedis。 但是这样写会在redis存储的时候遇到一些问题 这是因为redistemplat…

Java Kids-百倍提速【Mac IOS】

引言&#xff1a;当今社会&#xff0c;创新和提升效率已经成为了大家普遍的追求。无论是个人生活还是企业经营&#xff0c;我们都希望能够以更高的效率完成任务&#xff0c;节省时间和资源。因此&#xff0c;提速成为了一种时代的要求&#xff0c;而"Java Kids 百倍提速&q…

Android 10 中的隐私权变更

Android 10 中的隐私权变更 重大变更外部存储访问权限范围限定为应用文件和媒体在后台运行时访问设备位置信息需要权限以 Android 9 或更低版本为目标平台时自动授予访问权限在设备升级到 Android 10 后访问针对从后台启动 Activity 的限制标识符和数据移除了联系人亲密程度信息…

21-数据结构-内部排序-交换排序

简介&#xff1a;主要根据两个数据进行比较从而交换彼此位置&#xff0c;以此类推&#xff0c;交换完全部。主要有冒泡和快速排序两种。 目录 一、冒泡排序 1.1简介&#xff1a; 1.2代码&#xff1a; 二、快速排序 1.1简介&#xff1a; 1.2代码&#xff1a; 一、冒泡排序…

如何选择靠谱且适合自己的IC公司?(内附各大厂薪资加班情况分析)

近期&#xff0c;有不少同学私信手里有几个offer&#xff0c;却不知道该怎么选择 &#xff1f;这着实令找不到工作的小伙伴们羡慕啊&#xff0c;今天IC修真院就来给大家分析一下如何选择靠谱且适合自己的IC公司 &#xff1f; 目前市面上可选择的芯片公司有哪些&#xff1f; 关…

Qt/C++编写物联网组件/支持modbus/rtu/tcp/udp/websocket/mqtt/多线程采集

一、功能特点 支持多种协议&#xff0c;包括Modbus_Rtu_Com/Modbus_Rtu_Tcp/Modbus_Rtu_Udp/Modbus_Rtu_Web/Modbus_Tcp/Modbus_Udp/Modbus_Web等&#xff0c;其中web指websocket。支持多种采集通讯方式&#xff0c;包括串口和网络等&#xff0c;可自由拓展其他方式。自定义采…

【Python中图像相似性度量方法全面总结】

文章目录 概要图像相似性概念基于直方图的相似性度量基于SSIM的相似性度量基于特征相似性的度量基于深度学习的方法小结 概要 在当今充斥着图像的世界中&#xff0c;衡量和量化图像之间的相似性已经成为一项至关重要的任务。不论是在图像检索、内容推荐还是视觉搜索等现代计算…

js面向对象(工厂模式、构造函数模式、原型模式、原型和原型链)

1.封装 2. 工厂模式 function createCar(color, style){let obj new Object();obj.color color;obj.style style;return obj;}var car1 createCar("red","car1");var car2 createCar("green","car2"); 3. 构造函数模式 // 创建…

Linux虚拟机静态IP设置

1.环境配置 首先要准备好两台centos虚拟机&#xff0c;在高级篇部分可能有数据库主从复制&#xff0c;所以暂时先开两台虚拟机。 两台虚拟机需要更改&#xff1a; mac地址主机名ip地址UUID 1.更改主机名 更改虚拟机的主机名 vim /etc/hostname2.更改静态ip地址 /etc/sysc…