容器适配器——stack/queue/priority_queue

news/2024/5/21 11:10:45/文章来源:https://blog.csdn.net/Britney_dark/article/details/127171345

目录

一. stack

二. queue

三. priority_queue

1. empty(),top(),size()的实现

2. pop和push的实现


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

stack和queue中也可以存放元素,但在STL中并没有将其划分在容器的行列,而是将其称为容器适配器,这是因为stack和队列只是对其他容器的接口进行了包装。


一. stack

栈在初阶数据结构已经很熟悉了,这里不过是用C++再了解栈

  1. stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。

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

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

  • empty:判空操作

  • back:获取尾部元素操作

  • push_back:尾部插入元素操作

  • pop_back:尾部删除元素操作

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

没什么很大的区别,只是套用了别的容器,这里直接放代码:

template<class T, class Container = deque<T>>class stack{public:bool empty(){return con.empty();}size_t size(){return con.size();}void push(const T& x){con.push_back(x);}void pop(){con.pop_back();}T& top(){return con.back();}const T& top() const{return con.back();}private:Container con;};

二. queue

这里和上面同理。

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

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

直接上代码:

template <class T, class Container = deque<T>>class queue{public:bool empty(){return con.empty();}size_t size(){return con.size();}void push(const T& x){con.push_back(x);}T& front(){return con.front();}const T& front() const{return con.front();}T& back(){return con.back();}const T& back() const{return con.back();}void pop(){con.pop_front();}private:Container con;};

三. priority_queue

着重说一下优先级队列,这是接触到C++的第三个容器适配器

  1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。
  2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。
  3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。
  4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:
  • empty():检测容器是否为空
  • size():返回容器中有效元素个数
  • front():返回容器中第一个元素的引用
  • push_back():在容器尾部插入元素
  • pop_back():删除容器尾部元素

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

注意:需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。

也就是说:priority_queue在vector上使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。

注意:默认情况下priority_queue是大堆。(优先级队列默认大的优先级高,传的是less仿函数,底层是一个大堆,想控制小的优先级搞传greater仿函数,底层是一个小堆)

如下:

#include <vector>
#include <queue>
#include <functional> //greater算法的头文件
void TestPriorityQueue()
{// 默认情况下,创建的是大堆,其底层按照小于号比较vector<int> v{3,2,7,6,0,4,1,9,8,5};priority_queue<int> q1;for (auto& e : v)q1.push(e);cout << q1.top() << endl;// 如果要创建小堆,将第三个模板参数换成greater比较方式priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());cout << q2.top() << endl;
}

如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中提供>或者< 的重载。

以下是priority_queue的模板:

我们会发现第三个模板参数传入了一个比较的模板参数,也就是仿函数。

仿函数:一个声明了一个含有operator()成员函数的类,当创建好了对象后可以像函数那样使用这个对象,只不过这个函数功能是在一个类中的运算符operator()中实现,是一个函数对象,它将函数作为参数传递的方式来使用。

其实也就是说这里的比较从C语言中直接写<或者>变成了使用对象来比大小。

仿函数的实现如下:

    template<class T>struct less{bool operator()(const T& x, const T& y) const{return x < y;}};template<class T>struct greater{bool operator()(const T& x, const T& y) const{return x > y;}};

1. empty(),top(),size()的实现

这里我们将实现empty,top,size,pop,push的接口,前三个实现没什么难度,无非是封装容器的函数,如下:

        bool empty(){return con.empty();}size_t size(){return con.size();}const T& top(){return con[0];}

2. pop和push的实现

pop和push则会涉及到之前写的向下调整法和向上调整法。

push的实现如下:

        //默认建大堆void Adjustup(int child){int parent = (child - 1) / 2;while (child > 0){if(com(con[parent] ,con[child])){swap(con[child], con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& val){con.push_back(val);Adjustup(con.size() - 1);}

需要注意的是这里使用了仿函数,并且将比较对象com作为了成员变量,所以子节点和父节点在比较是像使用函数一样,这就是仿函数的特性。

pop的实现如下:

        //默认建大堆void Adjustdown(int parent){size_t child = parent * 2 + 1;while (child < con.size()){if (child + 1 < con.size() && com(con[child], con[child + 1])){++child;}if (com(con[parent], con[child])){swap(con[child], con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}void pop(){assert(!con.empty());swap(con[0], con[con.size() - 1]);con.pop_back();Adjustdown(0);}

这里和向上调整法一致,是使用仿函数来控制大堆或者小堆。

PS:这里在priority_queue类里创建比较对象是为了方便与C语言中的函数指针适配,也就是说,仍然可以适配函数指针。如何适配呢?具体查看以下的构造函数的实现:

priority_queue(const compare& comfun = compare()):com(comfun)
{}

这里使用了缺省的方式,当函数指针传进来,就会被初始化nullptr,但是如果传参数的时候是这样传:

 将函数名传过来而不是使用默认的,那么就可以匹配到想要的比较函数,可以正常进行比较,也就适配了函数指针。

这里再补充一个区间构造函数,既然是构造,自然也要建堆,但是这里为了效率我们使用向下调整法的方式建堆:

        template <class InputIterator>priority_queue(InputIterator first, InputIterator last, const compare& comp =             compare()):com(comp){//拷贝进入while (first != last){con.push_back(*first);++first;}//建堆向下调整法,最后一个非叶子结点处开始调整for (int i = (con.size() - 1 - 1) / 2; i >= 0; --i){Adjustdown(i);}}

自此,优先级队列也就实现完,下面是完整的代码实现方式:

    template<class T>struct less{bool operator()(const T& x, const T& y) const{return x < y;}};template<class T>struct greater{bool operator()(const T& x, const T& y) const{return x > y;}};template<class T, class Container = vector<T>, class compare = less<T>>class priority_queue{public:priority_queue(const compare& comfun = compare()):com(comfun){}template <class InputIterator>priority_queue(InputIterator first, InputIterator last, const compare& comp = compare()):com(comp){//拷贝进入while (first != last){con.push_back(*first);++first;}//建堆向下调整法,最后一个非叶子结点处开始调整for (int i = (con.size() - 1 - 1) / 2; i >= 0; --i){Adjustdown(i);}}bool empty(){return con.empty();}size_t size(){return con.size();}const T& top(){return con[0];}//默认建大堆void Adjustup(int child){int parent = (child - 1) / 2;while (child > 0){if(com(con[parent] ,con[child])){swap(con[child], con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& val){con.push_back(val);Adjustup(con.size() - 1);}//默认建大堆void Adjustdown(int parent){size_t child = parent * 2 + 1;while (child < con.size()){if (child + 1 < con.size() && com(con[child], con[child + 1])){++child;}if (com(con[parent], con[child])){swap(con[child], con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}void pop(){assert(!con.empty());swap(con[0], con[con.size() - 1]);con.pop_back();Adjustdown(0);}private:compare com;Container con;};

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

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

相关文章

C语言:数组参数、指针参数

目录 一.字符指针&#xff0c;指针数组&#xff0c;数组指针简单回顾 二.数组参数、指针参数 一维数组传参 二维数组传参 这里需要注意&#xff1a; 一级指针传参 思考 二级指针传参 思考 一.字符指针&#xff0c;指针数组&#xff0c;数组指针简单回顾 #include<std…

java虚拟机中的双亲委派机制

文章目录双亲委派机制工作原理工作场景调用过程三种加载器调用范围String类加载过程StringTest类加载过程双亲委派机制优点双亲委派机制 Java虚拟机对class文件采用的是按需加载的方式&#xff0c;也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象。而且加…

一些有趣的小项目合集~

pyqt人脸识别&#xff1a; nullhttps://www.jb51.net/article/168718.htmpyqt目标检测&#xff1a; 利用PyQt5为目标检测Faster-rcnn-Pytorch添加GUI界面&#xff08;二&#xff09;-python黑洞网 (pythonheidong.com)https://www.pythonheidong.com/blog/article/337144/e2d…

最常见的IMU:MPU6050

I2CI^2CI2C通讯 ​ I2CI^2CI2C is a two-wire interface comprised of the signals serial data (SDA) and serial clock (SCL). In general, the lines are open-drain and bi-directional. In a generalized I-C interface implementation, attached devices can be a maste…

优雅的处理参数校验以及异常

1、前言 编写控制层时&#xff0c;我们可能会自己去校验请求参数&#xff0c;就会出现这样的代码&#xff1a; if (StringUtils.isEmpty(memberSid)) {return new JsonResult(false, "参数memberSid为空"); } if (null test) {return new JsonResult(false, "…

油溶性PbS量子点近红外发射光PL800nm-1600nm

油溶性PbS量子点近红外发射光PL800nm-1600nm 油溶性PbS量子点产品&#xff0c;表面由疏水配体包覆&#xff0c;平均的量子产率为50%&#xff0c;储存时应避免阳光直射&#xff0c;4度密封暗处保存&#xff0c;可以为客户订制生产800nm&#xff5e;1600nm任一波长不同克数的产品…

叶毓睿:元宇宙发展与治理中,治理的主体是谁?治理的对象是谁?

中国移联元宇宙产业委员会联席秘书长、《元宇宙十大技术》著者之一、高效能服务器和存储技术国家重点实验室首席研究员叶毓睿&#xff1a;治理之可能性的关键在于延续性和开创性。 2022年9月24日&#xff0c;元宇宙产业委特别筹备的“发展与治理”2022元宇宙共治大会暨《元宇宙…

【JT-1/2电子式同步检查继电器】

1 用途 JT-1型同步检查继电器用于两端供电线路的自动重合闸线路中&#xff0c;其作用在于检查线路上电压的存在及线路上和变电站汇流排上电压向量间的相角差。 2 结构和原理 2.1 本继电器采用嵌入式安装&#xff0c;其主体部分系插拔式结构 2.2 本继电器主体部分与DT-1型同…

【Python基础面向对象】self、类变量和实例变量、__init__

哈喽兄弟们&#xff0c;我们接着上篇继续学习面向对象。 面向对象化编程所有的实例对象和实例方法都必须以self作为第一个参数&#xff0c;文章内容接上一章&#xff1a;Python面向对象编程基础之面向对象思想和特点、类和对象。这个系列将会很详细的解释清楚Python面向对象编程…

java实现多层级目录树详解

一&#xff0c;引言 在开发中&#xff0c;经常遇到前端需要实现一个多层级的目录树&#xff0c;那么后端就需要根据这种结构返回对应的数据&#xff0c;因此在这里记录一下本人在开发中是如何实现这个多层级的目录树。 二&#xff0c;建表建库 在建表时&#xff0c;需要注意…

(附源码)计算机毕业设计SSM悠哈出租车管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

模拟IC设计到底怎么学?给初学者一点建议

想必大家都知道&#xff0c;模拟IC设计非常难学。就拿最普遍的晶体管来说&#xff0c;我们分析它的时候必须首先分析直流偏置&#xff0c;其次在分析交流输出电压。可以说&#xff0c;这是一项相当复杂的工作。有些朋友一直吐槽模拟IC设计真的非常难学&#xff0c;那么到底该怎…

SWAT模型 建模方法、实例应用、高级进阶

目录 第一部分&#xff1a;【建模及实践】SWAT模型在水文水资源、面源污染模拟中的实践技术应用及典型案例分析 第二部分&#xff1a;【高级进阶】SWAT模型高阶应用暨无资料地区建模、不确定分析与气候变化、土地利用对面源污染影响模型改进及案例分析 基于ArcGIS的SWAT模型是…

yolov5-6.1的完全使用手册,含模型训练测试(可训练自己的数据集)

安装yolov5 安装命令如下下所示&#xff0c;包含了下载yolov5-6.1&#xff0c;及相关包安装命令。yolov5项目目前已经更新到6.2&#xff0c;支持对图像数据的分类&#xff0c;但使用较为麻烦&#xff0c;因此仅以6.1为例进行说明。安装yolov5后&#xff0c;切记不要安装wandb&…

条件区域循环的Sumif

问题:Sumif条件为D12:D16,求和区域从E3:E8向右,条件区域为B3:D8三列循环 函数解决:=SUMIF(OFFSET($B$3:$B$8,,MOD(COLUMN(C1),3)),$D12,E$3:E$8) 思路: 利用Mod(Column(C1),3),右拉生成0、1、2、0、1、2……这样的循环数 利用Offset,从B3:B8起,右拉生成向右偏移0、1、…

国民技术MCU之串口烧录

国民技术MCU串口烧录 前言 在我们使用国民技术单片机的时候&#xff0c;一般是用JLink SWD来烧录调试固件。 但是在某些情况下&#xff0c;比如需要刷写固件的现场没有JLink工具&#xff0c;采用批量生产、或者MCU在程序上电后SWD功能没有正常运行&#xff08;变砖&#xff0…

数据库概述06(视图)

视图 常见的数据库对象 表TABLE 表是存储数据的逻辑单元&#xff0c;以行和列的形式存在&#xff0c;列就是字段&#xff0c;行就是记录 数据字典 就是系统表&#xff0c;存放数据库相关信息的表。系统表的数据通常由数据库系统维护&#xff0c;程序员通常不应该修改&#xf…

一些有关多线程的‘‘八股文‘‘?!

目录 一. 常见的锁策略: 二. CAS 三.synchronized原理 四. HashTable, HashMap, ConcurrentHashMap 之间的区别: 五. 死锁的成因, 和解决方案: 一. 常见的锁策略: 1.乐观锁 vs 悲观锁: 描述的是两种不同的加锁态度 乐观:预测锁冲突概率不高,因此做的工…

2022年NPDP新版教材知识集锦--【第一章节】(2)

【制定战略的工具】 SWOT分析&#xff1a;由四个英文单词的首字母组合而成&#xff0c;分别是优势(Strengths)、劣势(Weaknesses)、机会(Opportunities)和威胁(Threats)。 ⚫优势&#xff1a;某企业或项目优于其他企业或项目的特点。 ⚫劣势&#xff1a;某企业或项目不如其他…

python学习笔记:numpy库,使用matpotlib库绘图

目录 一.Numpy库 1.什么是numpy? 2.Numpy数组和原生Python array数组之间的区别 3.Numpy数组 ​编辑 4.numpy数组的运算 5.numpy的索引&#xff0c;切片 二.matplotlib 1.绘制直线 2.绘制曲线 3.散点图绘制 4.多界面绘制 5.柱形图绘制 6.3D图形绘制 一.Numpy库 1.…