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

news2025/7/19 6:24:51

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.coloradmin.cn/o/1102679.html

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

相关文章

软信天成:流程管理是企业精细化管理的一大利器

流程管理&#xff08;BPM&#xff09;是指组织和管理内部或跨部门的工作流程&#xff0c;主要包括设计、建模、执行、监控和优化业务流程&#xff0c;确保工作按照标准化的步骤进行&#xff0c;从而提高效率、降低成本&#xff0c;促进业务增长。 一、流程管理生命周期五大步骤…

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

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

VScode platformio的使用

一、platformio 工程创建 打开vscode界面你会发现左下多了个家的小图标&#xff0c;点击这里就可以进入platformio。 在右侧Quick Access栏中&#xff0c;有4个选项。可以看得出来&#xff0c;我们这里直接点击创建一个新的工程。 点击New Project打开project配置界面&#x…

Android---自定义View

当 Android SDK 中提供的系统 UI 控件无法满足业务需求时&#xff0c;需要考虑自己实现 UI 控件。掌握自定义控件&#xff0c;是理解整套 Android 渲染体系的基础。自定义 UI 控件有2种方式&#xff1a; 继承系统提供的成熟控件&#xff08;比如 LinearLayout、RelativeLayout、…

美国跨境金融科技公司【Zolve】完成1亿美元融资

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;总部位于美国纽约的跨境金融科技公司Zolve近期宣布已经完成1亿美元融资。 本轮融资由CIM投资 该公司打算将这笔资金用于在英国、加拿大和澳大利亚的进一步扩张。 Zolve由创始人Raghunandan G领导&…

自由程序员想接私活?那你还不得知道这几个接单平台!最后一个就是宝藏!!

相信喜欢搞钱的程序员都知道&#xff0c;平常在平台上接点私活&#xff0c;利用闲暇时间接单是搞钱的常用套路&#xff0c;可是你确定你选对平台了吗&#xff1f;不管你是刚准备接单的小白&#xff0c;还是已经干了一段时间的老油条&#xff0c;都建议你看完本期文章&#xff0…

Spring框架(三)

1、代理模式&#xff1a; 二十三种设计模式中的一种&#xff0c;属于结构型模式。它的作用就是通过提供一个代理类&#xff0c;让我们在调用目标方法的时候&#xff0c;不再是直接对目标方法进行调用&#xff0c;而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标…

【译】快速开始 Compose 跨平台项目

原文&#xff1a; Compose Multiplatform application 作者&#xff1a;JetBrains 注意 Compose Multiplatform 中的 iOS 部分目前处于 Alpha 状态。以后可能会有不兼容的更改&#xff0c;届时也许需要手动进行迁移。 你可以使用这个模板来开发同时支持桌面、安卓和 iOS 的跨平…

极品三国新手攻略之进阶篇

尊敬的主公大人您好&#xff0c;首先恭喜您在游戏中取得的不俗成绩&#xff0c;相信您已经熟练掌握了不少玩法。今天&#xff0c;我们给大家奉上一份极品三国新手攻略之进阶篇&#xff0c;希望能为您提供有力的帮助。本篇攻略将为您深入分析游戏中武将、装备、试炼塔以及神兵等…

【微服务 SpringCloud】实用篇 · Ribbon负载均衡

微服务&#xff08;4&#xff09; 文章目录 微服务&#xff08;4&#xff09;1. 负载均衡原理2. 源码跟踪1&#xff09;LoadBalancerIntercepor2&#xff09;LoadBalancerClient3&#xff09;负载均衡策略IRule4&#xff09;总结 3. 负载均衡策略3.1 负载均衡策略3.2 自定义负载…

“升级是找死,不升级是等死”,GitLab CE 的痛苦升级之路

编者按&#xff1a;本文转载自公众号运维识堂&#xff0c;已经联系作者取得转载授权。 GitLab 在发展的十余年中&#xff0c;在国内积累了大量的 CE 用户&#xff0c;但是很多 CE 用户并不会跟随 GitLab 的发版节奏&#xff08;月度发版&#xff09;进行版本升级&#xff0c;在…

基于AT89C52+ADC0809+LCD1602的模数转换实验ptoteus仿真设计

一、仿真原理图&#xff1a; 二、仿真效果图&#xff1a; 三、仿真工程&#xff1a; 基于AT89C52ADC0809LCD1602的模数转换实验ptoteus仿真设计资源-CSDN文库

flask实战(问答平台)

问答平台项目结构搭建 先创建一个配置文件config.py&#xff0c;后面有些配置写在这里 #app.py from flask import Flask import configapp Flask(__name__) #绑定配置文件 app.config.from_object(config)app.route(/) def hello_world(): # put applications code herer…

数据结构-----红黑树的删除操作

目录 前言 一、左旋和右旋 左旋&#xff08;Left Rotation&#xff09; 右旋&#xff08;Right Rotation&#xff09; 二、红黑树的查找 三、红黑树的删除 1.删除的是叶子节点 1.1删除节点颜色为红色 1.2删除节点颜色为黑色 1.2-1 要删除节点D为黑色&#xff0c;兄弟节…

git 提交代码

提交代码流程 第一步:git status 第二步&#xff1a;git add . 第三步&#xff1a;git commit -m"xxx" 第四步&#xff1a;git pull origin dev 第五步&#xff1a;git push origin dev

HEIC转jpg

下载imagemagick,安装 https://imagemagick.org/archive/binaries/ImageMagick-7.1.1-20-Q16-HDRI-x64-dll.exe cmd D:\soft\ImageMagick-7.1.1-Q16-HDRI\magick.exe "C:\Users\Gamer\Downloads\iCloud 照片1\iCloud 照片\IMG_3889.HEIC" IMG_3889.jpg

不懂的东西

1、 2、 3、 4、 5、我看到那篇 Peace of mind 论文&#xff0c;有一个疑问&#xff0c;为什么论文里的量表用的频率指标&#xff1f;比如Some of the time&#xff0c; Not at all等&#xff0c;而PANAS用的是程度指标&#xff0c;比如moderately&#xff0c;a little等。…

一、初识 Elasticsearch:概念,安装,设置分词器

文章目录 01、初识 Elasticsearch正向索引和倒排索引索引MySQL与ES的概念映射安装ES分词器分词器的设置 01、初识 Elasticsearch 本次ES基于&#xff1a;7.12.1 版本 学习资源为&#xff1a;https://www.bilibili.com/video/BV1Gh411j7d6 什么是ES&#xff08;Elasticsearch&…

C/C++笔试易错与高频题型图解知识点(二)—— C++部分(持续更新中)

目录 1.构造函数初始化列表 1.1 构造函数初始化列表与函数体内初始化区别 1.2 必须在初始化列表初始化的成员 2 引用&引用与指针的区别 2.1 引用初始化以后不能被改变&#xff0c;指针可以改变所指的对象 2.2 引用和指针的区别 3 构造函数与析构函数系列题 3.1构造函数与析…

力扣环形链表(1)进阶环形链表(2)及环形链表的约瑟夫问题

为了加深对环形链表的理解和掌握&#xff0c;这两道题是很不错的选择。 这里所说环形链表不是一个圈圈的结构&#xff0c;而是带环链表。 链接&#xff1a;环形链表&#xff08;1&#xff09; 注意这里链表的长度 所以要注意链表是否为空 第一种方法&#xff0c;应该是比较容易…