【C++第十课 - stack_queue】stack、queue的使用、适配器模型stack、queue和priority_queue的底层实现、deque

news2024/9/21 14:42:02

目录

  • 一、stack使用
    • 1、push
    • 2、pop
    • 3、empty
    • 4、top
    • 题目
      • 1、最小栈
      • 2、栈的压入、弹出序
      • 3、逆波兰表达式求值
  • 二、queue的使用
    • priority_queue
    • 习题
  • 三、适配器
    • stack的底层实现
    • queue的底层实现
    • priority_queue的底层实现
    • 仿函数/函数对象
    • 函数指针
  • 四、deque

一、stack使用

stack是个容器适配器
stack想要访问里面所有的数据必须pop和top,不能使用范围for

1、push

插入向量
在这里插入图片描述

	stack<int> s;
	s.push(1);
	s.push(2);
	s.push(3);
	s.push(4);

2、pop

移除栈顶数据
在这里插入图片描述

3、empty

stack为空返回true
stack非空返回false

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4、top

取栈顶元素

题目

1、最小栈

https://leetcode.cn/problems/min-stack/
在这里插入图片描述
双栈解决
方案一
设计两个stack,一个stack存放数值,另一个stack存放最小值

存了这么多5有点浪费空间
改进方案二

在这里插入图片描述
方案二

_stpop的与_minst栈顶元素一样的时候,_minst也pop
存在的问题:当有好多个最小值是_minst要push进去多个,->改进:方案三

在这里插入图片描述

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、栈的压入、弹出序

用栈来模拟入栈和出栈过程

(1)如果pushV当前入栈的值和popV当前出栈的值一样,pushV向后移一位,popV向后移一位
(2)如果pushV当前入栈的值和popV当前出栈的值不一样,分两种情况
第一种情况:如果栈顶元素与popV当前出栈元素一样,popv向后移一位,栈顶元素弹出
第二种情况:如果栈为空或栈顶元素与popV当前的出栈元素不一样,将pushV当前入栈元素压入栈中,pushV向后移一位

之后开始对栈中元素按照popV的顺序进行出栈,如果对不上就是False

简化:先入栈,再判断

1、入栈序列当前数据入栈
2、栈顶元素与出栈序列进行比较
(1)相等,出栈,出栈序列++
(2)不相等
2的结束标志,栈为空或不相等
所有的结束标志:入栈序列走完

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pushV int整型vector 
     * @param popV int整型vector 
     * @return bool布尔型
     */
    bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {
        // write code here
        stack<int> s;
        size_t pushi = 0;
        size_t popi = 0;
        while(pushi < pushV.size())
        {
            s.push(pushV[pushi]);
            while(!s.empty() && s.top() == popV[popi])
            {
                s.pop();
                ++popi;
            }
            ++pushi;
        }
        return popi == popV.size();
    }
};

3、逆波兰表达式求值

逆波兰表达式求值

前缀表达式(波兰)
所有的符号都是在要运算的操作数字的前面出现。例如 /++abcde
中缀表达式
所有的符号都是在要运算的操作数字的中间出现。例如(a+b+c
d)/e
后缀表达式(逆波兰)
所有的符号都是在要运算的操作数字的后面出现。例如 abcd*++e/

在这里插入图片描述

二、queue的使用

在这里插入图片描述

容器container默认是deque(双端队列)

在这里插入图片描述

priority_queue

不是先进先出,是按优先级出
底层是:堆
是适配器,不是容器了
compare是比较的函数

在这里插入图片描述
在这里插入图片描述

习题

在这里插入图片描述
方法一

在这里插入图片描述

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> q;
        queue<int> qlayer;
        vector<vector<int>> vv;
        int layer = 1;
        if(root)
        {
            q.push(root);
            qlayer.push(layer);
        }
        while(!q.empty())
        {
            vector<int> v;
            while(qlayer.front() == layer )
            {
                TreeNode* cur = q.front();
                q.pop();
                v.push_back((*cur).val);
                if(cur->left)
                {
                  q.push(cur->left);
                  qlayer.push(layer + 1);
                }
                if(cur->right)
                {
                    q.push(cur->right);
                    qlayer.push(layer + 1);
                }
                qlayer.pop();
            }
            vv.push_back(v);
            ++layer;
        }
        return vv;
    }
};

方法二

三、适配器

适配器就是一个设计模式
由容器(string、vector、list、deque)封装、转换而成的,底层数据的管理不是由自己负责的
默认容器:
stack -> deque
queue -> deque
priority_queue -> vector

stack的底层实现

站和队列的底层实现都是复用的容器(string、vector、list)

在这里插入图片描述

	template<class T, class Container = deque<T>>
	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:
		Container _con;
	};
在这里插入代码片

queue的底层实现

在这里插入图片描述

	template<class T, class Container = deque<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;
	};

priority_queue的底层实现

在这里插入图片描述
是优先级队列,优先级高的先出,因此用堆进行实现

	template<class T, class Container = vector<T>>
	class priority_queue
	{
	public:
		void adjust_up()
		{
			int child = _con.size() - 1;
			int parent = (child - 1) / 2;

			while (parent >= 0)
			{
				if (_con[child] > _con[parent])
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}

		}
		void push(const T& x)
		{
			_con.push_back(x);
			adjust_up();
		}
		void adjust_down()
		{
			int parent = 0;
			int left = parent * 2 + 1; 
			int right = parent * 2 + 2;
			int size = _con.size();
			while (left < size)
			{
				int big = left;
				if (right < size && _con[right] > _con[left])
				{
					big = right;
				}
				if (_con[big] > _con[parent])
				{
					swap(_con[big], _con[parent]);
					parent = left;
					left = parent * 2 + 1;
					right = parent * 2 + 2;
				}
				else
				{
					break;
				}
			}
		}
		//优先出优先级高的
		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjust_down();
		}
		const T& top()
		{
			return _con[0];
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
	};

priority_queue里面用的仿函数–第三个模板参数

仿函数/函数对象

为了解决函数指针的缺陷
回调函数:这个函数已经写好了,在用到它的时候再去调它(C语言用这个)
Compare可以定义成成员对象,也可以在用的时候创建一个Compare com;
模板参数:传的是类型,编译的时候传递

namespace zyh
{
	template<class T>
	class less
	{
	public:
		bool operator()(T x, T y)
		{
			return x < y;
		}
	};
	template<class T>
	class greater
	{
	public:
		bool operator()(T x, T y)
		{
			return x > y;
		}
	};


	template<class T, class Container = vector<T>, class Compare = greater<T>>
	class priority_queue
	{
	public:
		void adjust_up()
		{
			int child = _con.size() - 1;
			int parent = (child - 1) / 2;

			while (parent >= 0)
			{
				if (_com(_con[child], _con[parent]))
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}

		}
		void push(const T& x)
		{
			_con.push_back(x);
			adjust_up();
		}
		void adjust_down()
		{
			int parent = 0;
			int left = parent * 2 + 1; 
			int right = parent * 2 + 2;
			int size = _con.size();
			while (left < size)
			{
				int big = left;
				if (right < size && _com(_con[right], _con[left]))
				{
					big = right;
				}
				if (_com(_con[big], _con[parent]))
				{
					swap(_con[big], _con[parent]);
					parent = left;
					left = parent * 2 + 1;
					right = parent * 2 + 2;
				}
				else
				{
					break;
				}
			}
		}
		//优先出优先级高的
		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjust_down();
		}
		const T& top()
		{
			return _con[0];
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
		Compare _com;
	};
}

在这里插入图片描述
模板参数不仅能在类里面传递还能在函数里面传递
在这里插入图片描述

上面是类模板,只能穿仿函数。如果传函数指针,类里面也是将它转换成类型还是拿不到函数指针
下面是函数模板,可以传仿函数对象、函数指针。能传函数指针是因为,可以根据函数指针推出类型,同时参数那也可以得到函数指针。

函数指针

传递的是对象是参数变量,运行时传递的

在这里插入图片描述

四、deque

双端队列,但不是队列。就像优先级队列也不是队列

拥有list和vector的所有功能,尾插尾删、头插头删、[ ]
[ ]的效率没有vector的高

vector
优点:物理结构连续存储的优势
(1)下标随机访问
(2)缓存命中高
缺点:
(1)前面插入删除效率低
(2)扩容有消耗
list
优点:
(1)扩容没有消耗
(2)随机插入删除效率高
缺点:
(1)不支持下标随机访问
(2)缓存命中低

在这里插入图片描述

deque
优势:头插头删,尾插尾删很不错
不足:
随机访问效率没有vector高
访问第i个值,【假设保持每个buff一样大,都是10】
如果第一个buff不是从头开始的,不在第一个buff,那么i -= 第一个buff的数据个数
第i/10个buff中
在这个buff的第i%10位置
中间插入删除如何实现?
如果不需要保持每个buff一样大,只能挪动数据
如果不需要保持每个buff一样大,可以对当前buff,扩容或者挪动数据

结论
1、小标随机访问,效果不错,但是跟vector仍有差距
2、中间插入删除,效率差

如果一个适配器经常头插头删、尾插尾删 -> deque
如果少量的下标访问 -> 可以用deque
如果大量的下标访问 -> 需要用vector
如果中间插入删除 -> list

在这里插入图片描述

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

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

相关文章

深入探索Python库的奇妙世界:赋能编程的无限可能

在编程的浩瀚宇宙中&#xff0c;Python以其简洁的语法、强大的功能和广泛的应用领域&#xff0c;成为了众多开发者心中的璀璨明星。而Python之所以能够如此耀眼&#xff0c;很大程度上得益于其背后庞大的库生态系统。这些库&#xff0c;如同一块块精心雕琢的积木&#xff0c;让…

ffmpeg图片视频编辑器工具的安装与使用

title: ffmpeg图片视频编辑器工具的安装与使用 tags: [ffmpeg, 图片, 音频, 视频, 工具, 流媒体] categories: [工具, ffmpeg] FFmpeg是一个开源的命令行工具&#xff0c;广泛用于处理视频和音频文件&#xff0c;包括转换格式、剪辑、混流、解码、编码等。以下是一些基本的FFmp…

【全面讲解下iPhone新机官网验机流程】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

nginx配置反向代理-CSDN

客户需求 1、实现通过域名访问税金的发票服务&#xff08;路径格式要求&#xff1a;https://www.xxx.com&#xff09; nginx的部署 前提 1、客户在局域网内已实现通过https://ip:port/stms访问税金平台 2、客户已获取https的SSL证书 3、客户申请的外网ip和域名已绑定 部署…

为什么要设计DTO类

为什么要使用DTO类&#xff0c;下面以新增员工接口为例来介绍。 新增员工 1.1 需求分析和设计 1.1.1 产品原型 一般在做需求分析时&#xff0c;往往都是对照着产品原型进行分析&#xff0c;因为产品原型比较直观&#xff0c;便于我们理解业务。 后台系统中可以管理员工信息…

WEB自动化框架封装MySQL连接及sql断言教程

为了在Web自动化测试中连接MySQL数据库并进行SQL断言&#xff0c;您可以按照以下步骤&#xff1a; 安装MySQL Connector/Python驱动程序&#xff0c;并导入它。 使用Connector/Python创建一个连接对象&#xff0c;指定所需的主机名、用户名、密码和数据库名。 创建一个游标对…

linux-虚拟内存-虚拟cpu

1、进程&#xff1a; 计算机中的程序关于某数据集合上的一次运行活动。 狭义定义&#xff1a;进程是正在运行的程序的实例&#xff08;an instance of a computer program that is being executed&#xff09;。广义定义&#xff1a;进程是一个具有一定独立功能的程序关于某个…

【三维向量旋转】基于Matlab的三维坐标旋转

一、问题描述 若空间中存在三个点A,B,C&#xff0c;其中A点是不动点&#xff0c;B点是当前方向向量上的一个点&#xff0c;C是目标方向上的一个点。如果要让AB向量沿着BC方向进行旋转&#xff0c;使得AB最终旋转到AC。这个过程就是三维向量的旋转过程。我们关注的是这个过程&am…

JAVA 课设 满汉楼餐厅点餐系统

一、代码详解 1.总体结构展示 2.总体代码 2.1 libs文件 链接&#xff1a;https://pan.baidu.com/s/1nH-I7gIlsqyMpXDDCFRuOA 提取码&#xff1a;3404 2.2 配置的德鲁连接池 #keyvalue driverClassNamecom.mysql.cj.jdbc.Driver urljdbc:mysql://localhost:3306/mhl?rewriteBa…

爱了!8款超好用的PC端办公软件!

AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频https://aitools.jurilu.com/ 你电脑中用的最久的软件是哪些&#xff1f;以下是否有你曾经使用过的软件呢&#xff1f;工欲善其事&#xff0c;必先利其器&#xff0c;今天继续…

打造属于自己的脚手架工具并发布到npm仓库

一、创建项目 使用 npm init -y 创建项目创建项目入口文件 index.js在 package.json 中添加 bin 字段使用 npm link 命令将文件映射至全局&#xff0c;使可以在本地测试 zp 命令 // "zp" 为用于全局执行脚手架的命令&#xff0c;vue-cli中使用的是vue命令 "bi…

STM32-I2C

本内容基于江协科技STM32视频学习之后整理而得。 文章目录 1. I2C通信1.1 I2C通信简介1.2 硬件电路1.3 I2C时序基本单元1.3.1 起始条件和终止条件1.3.2 发送一个字节1.3.3 接收一个字节1.3.4 发送应答和接收应答 1.4 I2C时序1.4.1 指定地址写1.4.2 当前地址读1.4.3 指定地址读…

利用docker搭建漏洞环境,使用SSRF+Redis写入centos以及ubuntu的公钥,实现免密登录

一、实验环境 kali:在kali中搭建docker容器环境&#xff0c;这里我主要是使用第一个&#xff1b; redis作为一种数据库&#xff0c;它可以将数据写入内存中去&#xff0c;我们通过利用ssrf请求&#xff0c;实现服务器对自己的公钥写入&#xff0c;从而实验免密登录&#xff1b;…

el-table 树形数据与懒加载 二级数据不展示

返回的数据中 children和hasChildren只能有一个&#xff0c;不能同时存在&#xff0c;否则加载数据会失败

优化后Day53 动态规划part11

LC1143最长公共子序列 1.dp数组的含义&#xff1a;dp[i][j]表示以下标i结尾的text1子序列和以下标j结尾的text2子序列的最长公共子序列 2. 初始化&#xff1a;跟LC718一样&#xff0c;i结尾的需要初始化&#xff0c;i-1结尾不需要初始化 3. 递推公式 如果charAt(i)charAt(j)&…

集成测试技术栈

前端 浏览器操作&#xff1a;playwright、selenium 后端 testcontainercucumbervitestcypressmsw

Threejs将场景生成全景图导出

实现思路&#xff1a; 创建全景相机CubeCamera&#xff08;六个方位的透视相机&#xff09;并渲染场景 读取六个面的纹理数据 填充进canvas中 即可按照常规的canvas导出图片了 demo https://gitee.com/honbingitee/three-template-next.js/tree/HDR 核心代码 const cubeRender…

《python程序语言设计》2018版第5章第53题利用turtle绘制sin和cos函数 sin蓝色,cos红色和52题类似

直接上题和代码 5.53 &#xff08;Turtle&#xff1a;绘制sin和cos函数&#xff09;编写程序绘制蓝色的sin函数和红色的cos函数。 代码和结果 turtle.speed(10) turtle.penup() # sin 用蓝色 turtle.color("blue") #这道题和上道题一样&#xff0c;先把turtle放到起始…

数列结构(3.9)——队列应用

树的层次遍历 树的层次遍历&#xff0c;也称为树的广度优先遍历&#xff0c;是一种按照树的层次顺序&#xff0c;从上到下、从左到右遍历树中所有节点的算法。在二叉树中&#xff0c;这种遍历方式通常使用队列来实现。下面是层次遍历的基本步骤&#xff1a; 创建一个空队列&a…

排序(2)

我们在排序&#xff08;1&#xff09;中说到选择排序的代码&#xff1a; void SelectSort(int* a,int n) {int begin0,endn-1;int minibegin,maxbegin;for(int ibegin1;i<end;i){if(a[i]>a[max]){maxii;}if(a[i]<a[mini]){minii;}begin;--end;}Swap(&a[beign],&a…