C++容器适配器与stack,queue,priority_queue(优先级队列)的实现以及仿函数(函数对象)与deque的简单介绍

news2024/10/7 8:32:01

🎉个人名片:

🐼作者简介:一名乐于分享在学习道路上收获的大二在校生
🙈个人主页🎉:GOTXX
🐼个人WeChat:ILXOXVJE
🐼本文由GOTXX原创,首发CSDN🎉🎉🎉
🐵系列专栏:零基础学习C语言----- 数据结构的学习之路----C++的学习之路
🐓每日一句:如果没有特别幸运,那就请特别努力!🎉🎉🎉 ————————————————

🎉文章简介:

🎉本篇文章将 学习c++容器适配器与stack,queue应用适配器实现 相关知识进行分享!
💕如果您觉得文章不错,期待你的一键三连哦,你的鼓励是我创作动力的源泉,让我们一起加 油,一起奔跑,让我们顶峰相见!!!🎉🎉🎉
——————————————————

一.容器适配器

一.什么是容器适配器

容器适配器是一种设计模式,它通过封装现有的序列容器类,并重定义其成员函数,以提供不同的功能或满足特定的需求。这种适配器类似于电源适配器,它将不兼容的电源(如不同国家的电压标准)转换可用的电源(即适合电器使用的电压),以便用户能够方便地使用各种电器。

在计算机编程中,容器适配器允许程序员使用已经存在的序列容器类(如vector、deque、list等),同时获得预定义的特定功能,如stack实现后进先出(LIFO)存储、queue实现先进先出(FIFO)存储、以及priority_queue实现基于优先级的存储。

容器适配器本质上是容器的一种变体,它利用了其他基础容器模板类中已经实现的成员函数,并在必要时添加或创新自己的成员函数。

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

二.STL中stack,queue在底层中的结构

STL中stack与queue不属于容器,而是容器适配器,他们是基于已经存在的类(容器)上面,对该类(容器)的接口进行了包装,STL中stack和queue默认使用deque;

们可以通过文档发现:
如图:
在这里插入图片描述
在这里插入图片描述

二.相关适配器的介绍及实现

简单的说,这里的适配器的实现,就是在一个类里面,定义一个其他容器的对象A(能支持该适配器B的功能),然后在实现 B 所需要的函数的时候,在函数里面调用 A的成员函数 来实现 B的函数 或则 B函数 的某部分,然而实现B;
可以结合下面的例子看看:

一.stack

一.stack的介绍

stack的文档 link
1. stack是一种容器适配器,具有 后进先出 的特点,是只允许在一端进行删除,插入,提取操作的容器适配器;

2. stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。

3. stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以下操作:

empty:判空操作
back:获取尾部元素操作
push_back:尾部插入元素操作
pop_back:尾部删除元素操作

4. 标准容器vector、deque、list均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器,默认情况下使用deque。

后进先出特点
在这里插入图片描述

相关函数
在这里插入图片描述

二.实现:
  //这里的Cintainer不确定是什么,默认不传我们给的是deque<int>,和库里面一致
	template<class T, class Container=deque<int>>  //模板参数是传类型
	class stack
	{
	public:
		stack()         //初始化,会去调用对象_con的构造函数
			:_con()     //这里_con默认是deque
		{
		}
		void push(const T& x)    //这里成员函数名可以自己随便修改,这里是为了和库里面的一致
		{
			_con.push_back(x);    //这里调用的函数必须是对象_con的成员函数,并且名字必须相同
		}
		void pop()         
		{
			_con.pop_back();   //下面的调用和上面的都类似
		}
		T& top()
		{
			return _con.back();   //调用_con的取头数据函数
		}
		bool empty()
		{
			return _con.empty();    //调用_con的判空函数
		}
		size_t size()
		{
			return _con.size();    //调用_con的size()函数
		}
	private:     
		Container _con;       //声明一个Container对象
	};

stack的实现完全就是自己什么都不做,全去调用Contaoner的成员函数就可以实现的,下面的queue也是一样;

二.queue

一.queue的介绍

queue文档链接: link

1. 队列是一种容器适配器,专门用于在先进先出(比如现实中取号排队的问题,越早取号的先)中操作,其中从容器一端插入元素,另一端提取元素;

2. 队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。

3. 底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:

empty:检测队列是否为空
size:返回队列中有效元素的个数
front:返回队头元素的引用
back:返回队尾元素的引用
push_back:在队列尾部入队列
pop_front:在队列头部出队列

4. 标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque。

先进先出 特点
在这里插入图片描述
函数使用
在这里插入图片描述

二.实现

与stack的实现一样

template<class T,class Container=deque<int>>   //库里面一致,默认是deque<int>
class quque
{
public:
	quque()
		:_con()
	{}
	void push(const T& x)
	{
		_con.push_back(x);    //调用_con的成员函数
	}
	void pop()
	{
		_con.pop_front();
	}
	T& top()
	{
		return _con.front();
	}
	size_t size()
	{
		return _con.size();
	}
	bool empty()
	{
		return _con.empty();
	}
private:
	Container _con;
};

三.priority_queue

一.priority_queue的介绍

priority_queue文档链接: link

1. 优先队列是一种容器适配器,类似于堆,默认情况下是大堆,即堆顶的元素总是它所包含的元素中最大的;

2. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。

3. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。因为vector支持下标随机访问

4.需要支持随机访问迭代器,以便始终在内部保持堆结构;
支持以下操作:

mpty():检测容器是否为空
size():返回容器中有效元素个数
front():返回容器中第一个元素的引用
push_back():在容器尾部插入元素
pop_back():删除容器尾部元素

函数使用
在这里插入图片描述

.实现

仿函数的简单介绍

仿函数,就是使一个类的使用看上去像一个函数。其实现就是类中实现一个operator(),这个类就有了类似函数的行为,就是一个仿函数类了;
有了仿函数类过后,再结合模板使用,就可以使一些需要重复使用的代码独立出来,以便下次复用,这样有利于资源的管理(这点可能是它相对于函数最显著的优点了)。

就比如下面我们所需要实现的优先队列,默认的是大堆(如图,库里面是反着的,less是大堆,greater是小堆),当我们想要小堆的时候,就需要用仿函数,这样只需要我们再使用优先级队列时改变传的模板参数即可;
在这里插入图片描述

向上调整与向下调整思想及图解链接: link

template<class T>
class lesser               //定义一个类
{
public:
	bool operator()(const T& x, const T& y)   //重载operator()
	{
		return x < y;                  //小于的比较逻辑
	}
};
template<class T>                 //定义一个类
class greater
{
public:
	bool operator()(const T& x, const T& y)     //重载operator()
	{
		return x > y;              //大于的比较逻辑
	}
};
namespace P
{                         
	template<class T, class Container=vector<int>,class Compare= less<int> >
	class priority_quque
	{
	public:
		priority_quque()
			:_con()
		{}
		void AdjustUp(int child)
		{
			Compare _com;
			int parent = (child - 1) / 2;
			while (parent >= 0)
			{
				if(_com(_con[child],_con[parent]))
				{
					std::swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}
		void AdjustDown(int parent)
		{
			Compare _com;
			int child = parent * 2 + 1;

			while (child < _con.size())
			{
				if (child + 1 < _con.size() && _com(_con[child+1] , _con[child]))
				{
					++child;
				}
				//如果父亲比孩子小,交换
				if(_com(_con[child],_con[parent]))
				{
					std::swap(_con[parent], _con[child]);
					parent = child;                           //向下走
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		void push(const T& x)
		{
			_con.push_back(x);    //尾插一个数据
			AdjustUp(size() - 1);  //然后向上调整
		}
		void pop()
		{
			std::swap(_con[0], _con[size() - 1]);   //堆顶与最后一个元素交换,然后删除最后一个元素,然后从堆顶开始,向下调整
			_con.pop_back();
			AdjustDown(0);     //向下调整
		}
		T& top()
		{
			return _con.front();
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
	};

}

三.deque的介绍

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

所说的来连续,并不是说都是连续的,在底层,deque是一段一段的数组,数组中存储的数据,然后有一个指针数组存储每一个数组的地址,这样,与vector比较,头部插入和删除时,不需要搬移元素,效率特别高,而且在扩容时,也不需要搬移大量的元素,因此其效率是必vector高的。
与list比较,其底层是连续空间,空间利用率比较高,不需要存储额外字段。

在这里插入图片描述

但是有一个致命的缺陷是:中间插入和删除效率与下标随机访问的效率不高,这个缺陷是底层物理结构所导致的;

为什么选择deque作为stack和queue的底层默认容器?

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

1.stack和queue不需要遍历(因此stack和queue没有迭代器),只需要在固定的一端或者两端进行操作。
2. 在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据);queue中的元素增长时,deque不仅效率高,而且内存使用率高。
结合了deque的优点,而完美的避开了其缺陷。

请添加图片描述

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

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

相关文章

简单的溯源取证

环境准备: Linux虚拟机:内网部署蜜罐探测系统 。(192.168.XX.XX) windows虚拟机:有FTP弱口令漏洞的web服务 (受害机器) (192.168.125.134) kali Linux虚拟机:攻击机服务端 。 (192.168.125.130) MAC:管理员电脑。(192.168.XX.XX) 一、利用kailiLinuxmsf生成windows木马文件…

Maven项目 快速修复log4j 漏洞

1、log4j 漏洞介绍 log4j的漏洞介绍以及原理请参考文章 &#xff0c;网址详见下面文章 Log4j漏洞原理及修复_linux log4j漏洞修复方案-CSDN博客&#xff0c;遇到这个漏洞要升级log4j 的jar包到2.17.0 以上。 2、项目快速处理方案 由于maven 管理jar 的spring 项目或者…

dpdk二层转发环境搭建-二

文章目录 前言虚拟机的网络拓扑结构网络拓扑结构网络配置 DPDK的准备工作DPDK的编译网卡绑定 测试 前言 我之前尝试通过namespace&#xff0c;搭建dpdk的测试环境&#xff0c;但是对于tcp有点问题&#xff0c;而且过程也比较麻烦&#xff0c;见&#xff1a; dpdk网络转发环境的…

es文档操作命令

文档操作 documents 创建数据&#xff08;put&#xff09; 向 user 索引下创建3条数据 PUT /user/_doc/1 {"name":"zhangsan","age":18,"sex":"男","info":"一顿操作猛如虎&#xff0c;一看工资2500"…

【OpenCV • c++】图像平滑处理(1) —— 线性滤波

文章目录 一、平滑处理二、图像滤波三、邻域算子与线性邻域滤波四、方框滤波代码演示 一、平滑处理 平滑处理也称为模糊处理&#xff0c;是一种简单且使用频率很高的图像处理方法&#xff0c;平滑处理的用途有很多&#xff0c;最常见的是用来减少图像上的噪点或者失真。在涉及到…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:EffectComponent)

特效合并容器组件&#xff0c;用于子节点特效绘制的合并&#xff0c;实现特效的绘制性能优化。 说明&#xff1a; 该组件从API Version 10开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 该组件为系统接口。 目前该组件仅支持子组件背景…

[java基础揉碎]Object类详解

目录 equals方法: hashCode: toString: finalize: equals方法: 和equals对比 1.: 既可以判断基本类型&#xff0c;又可以判断引用类型 2.: 如果判断基本类型&#xff0c;判断的是值是否相等。示例: int i10; double d10.0; 3.:如果判断引用类型&#xff0c;判断的是地址是…

信息检索(十三):On Complementarity Objectives for Hybrid Retrieval

On Complementarity Objectives for Hybrid Retrieval 摘要1. 引言2. 相关工作2.1 稀疏和密集检索2.2 互补性 3. 提出方法3.1 Ratio of Complementarity (RoC)3.2 词汇表示&#xff08;S&#xff09;3.3 语义表示&#xff08;D&#xff09;3.4 互补目标 4. 实验4.1 实验设置4.2…

哪里有视频素材网站免费下载?高清烟花视频素材哪里有?

如果你在寻找那些能点亮夜空的绚丽烟花视频素材&#xff0c;或者无水印的高清视频素材&#xff0c;那下面这些资源网站将会是你的宝库。今天&#xff0c;我要分享给你一些最佳的无水印视频素材下载网站&#xff0c;让你的视频制作闪耀起来。 1.蛙学府 这个网站是视频创作者的天…

windows使用docker运行TP6使用swoole内置http服务

1&#xff0c;下载docker-Windows客户端 下载地址&#xff1a;https://www.docker.com/products/docker-desktop docker --version #查看docker版本 docker-compose --version #查看docker-compose版本 2&#xff0c;安装环境 使用一键安装包&#xff1a;https://gitee.com/yes…

如何在Linux CentOS部署宝塔面板并实现固定公网地址访问内网宝塔

文章目录 一、使用官网一键安装命令安装宝塔二、简单配置宝塔&#xff0c;内网穿透三、使用固定公网地址访问宝塔 宝塔面板作为建站运维工具&#xff0c;适合新手&#xff0c;简单好用。当我们在家里/公司搭建了宝塔&#xff0c;没有公网IP&#xff0c;但是想要在外也可以访问内…

Android和IOS应用开发-Flutter 应用中实现记录和使用全局状态的几种方法

文章目录 在Flutter中记录和使用全局状态使用 Provider步骤1步骤2步骤3 使用 BLoC步骤1步骤2步骤3 使用 GetX&#xff1a;步骤1步骤2步骤3 在Flutter中记录和使用全局状态 在 Flutter 应用中&#xff0c;您可以使用以下几种方法来实现记录和使用全局状态&#xff0c;并在整个应…

深度学习pytorch——基本数据类型创建Tensor(持续更新)

声明&#xff1a;本深度学习笔记基于课时18 索引与切片-1_哔哩哔哩_bilibili学习而来 All is about Tensor 定义&#xff1a;Tensors are simply mathematical objects that can be used to describe physical properties, just like scalars and vectors. In fact tensors a…

粤嵌6818开发板通过MobaXterm使用SSH连接开发板

链接&#xff1a;https://pan.baidu.com/s/18ISP4Ub1HtQx6jCvTQTUHw?pwdfjmu 提取码&#xff1a;fjmu 1.把SSH_config.tar.bz 下载到开发板中 2.解压 SSH_config.tar.bz 解压命令&#xff1a;tar -xzvf SSH_config.tar.bz 3.配置SSH 进入SSH/openssh目录&am…

【深度长文】聊一聊 Java AbstractQueuedSynchronizer 以及在 ReentrantLock 中的应用

文章目录 AQS 原理简述内部数据结构公平锁 vs. 非公平锁ReentrantLock 非公平锁ReentrantLock 公平锁 AQS 源码分析加锁过程addWaiteracquireQueuedshouldParkAfterFailedAcquirecancelAcquire 解锁过程unparkSuccessor AbstractQueuedSynchronizer (AQS) 是 Java 并发包中&…

【Qt问题】解决已经下载好的qt怎么添加或卸载其他组件

问题描述&#xff1a; 使用一段时间Qt以后发现需要用到某个组件&#xff0c;比如Qt Webengine这个组件等&#xff0c;而此时我又不可能把Qt卸载了&#xff0c;重新安装一次。 解决办法&#xff1a; 其实Qt提供了安装或卸载其他组件的方式&#xff0c;以下是操作步骤&#xff…

nuxt3项目总结

nuxt3项目总结 仓库 前言 大半年的时间&#xff0c;项目从秋天到春天&#xff0c;从管理后台到APP再到数据大屏&#xff0c;技术栈从vue3到uniApp再到nuxt3&#xff0c;需求不停的改&#xff0c;注释掉代码都快到项目总体的三分之一。 一、准备-搭建项目架子 1.1 创建一个…

windows无法启动HV主机服务 服务(位于本地计算机上) 错误 1068:依赖服务或组无法启动

背景: LZ本地装了VMware Workstation虚拟机,里面装了Oracle, 又在Docker里装了PostgreSQL, 操作系统是Windows10 专业版 如果启动VM,就报这个错Device/Credential Guard 不兼容 参考这个博客,就可以解决 与Device/Credetial Guard不兼容 我用到的是方法二, 但是想用Docker时, …

吴恩达机器学习笔记 二十四 决策树模型 学习过程 什么时候停止分裂 如何选择结点特征

案例&#xff1a;识别小猫&#xff0c;上面这个分类的特征 x 采用分类值&#xff08;几个离散的值&#xff09; 决策树最顶端的结点称根结点(root node)&#xff0c;除了根结点和叶子结点之外的叫决策结点(decision node)&#xff0c;最底层的叫叶子结点(leaf node)&#xff0c…

JVM的双亲委派模型和垃圾回收机制

jvm的作用是解释执行java字节码.java的跨平台就是靠jvm实现的.下面看看一个java程序的执行流程. 1. jvm中的内存区域划分 jvm也是一个进程,进程在运行过程中,要行操作系统申请一些资源.这些内存空间就支撑了后续java程序的执行. jvm从系统申请了一大块内存,这块内存在java程序使…