【C++STL精讲】优先级队列(priority_queue)与双端队列(deque)

news/2024/4/30 3:12:29/文章来源:https://blog.csdn.net/gllll_yu/article/details/130274625

在这里插入图片描述

文章目录

  • 💐专栏导读
  • 💐文章导读
  • 🌷优先级队列——priority_queue
    • 🌸什么是优先级队列?
    • 🌸优先级队列的基本使用
    • 🌸什么是仿函数?
    • 🌸优先级队列的模拟实现
  • 🌷双端队列——deque
    • 🌸deque的优点与缺点
    • 🌸deque的原理

💐专栏导读

🌸作者简介:花想云,在读本科生一枚,致力于 C/C++、Linux 学习。

🌸本文收录于 C++系列,本专栏主要内容为 C++ 初阶、C++ 进阶、STL 详解等,专为大学生打造全套 C++ 学习教程,持续更新!

🌸相关专栏推荐:C语言初阶系列C语言进阶系列数据结构与算法

💐文章导读

本章我们将继续认识一种新的容器适配器——优先级队列(priority_queue)与容器——双端队列(deque)。本文将介绍什么是优先级队列以及优先级队列的基本使用与模拟实现,以及通过listvector的对比去学习deque
在这里插入图片描述

🌷优先级队列——priority_queue

🌸什么是优先级队列?

priority_queuestackqueue相同,都是一种容器适配器。如果你有一定的数据结构基础,或者是曾经阅读过我的数据结构专栏,那么优先级队列就并不是一个什么高大上的东西,它其实就是我之前讲过的——

优先级队列允许你以任意顺序插入元素,并且每次弹出的元素是当前优先级最高(及最大或最小)的元素。在priority_queue中,元素的插入顺序不影响元素的优先级,而是根据其优先级属性进行排序。

🌸优先级队列的基本使用

  • 🍁包含头文件 < queue >;
#include <queue>
  • 🍁定义一个priority_queue对象;
	priority_queue<int> pq;
  • 🍁向队列中插入一个元素;
	pq.push(1);pq.push(5);pq.push(2);
  • 🍁从队列中弹出一个元素(该元素为队列内优先级最高的元素);
	pq.pop();
  • 🍁返回队列中优先级最高的元素(及堆顶的元素);
	cout << pq.top() << endl;
  • 🍁返回队列中的元素数量;
	cout << pq.size() << endl;
  • 🍁判断队列是否为空;
	//empty()if (pq.empty()){cout << "Queue is empty" << endl;}else{cout << "Queue is not empty" << endl;}

特别注意

优先级队列默认是建大堆,也就是元素的值越大,优先级越高。我们可以通过一个传递模板参数来控制优先级的判别。所以,优先级队列在设计的时候用到了3个模板参数,而我们上一章所学习的stackqueue则是2个模板参数,如图:

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

	// 默认情况下,创建的是大堆,其底层按照小于号比较priority_queue<int> pq1;// 如果要创建小堆,将第三个模板参数换成greater比较方式// 记得包含greater算法的头文件——#include <functional>priority_queue<int, vector<int>, greater<int>> pq2;

第三个模板参数仅仅只有比较大小的作用,我们也可以自己实现这样一个模板类来传递。像图中Compare这样的类所创建的对象,我们通常称它为——仿函数。因为该类的对象可以像函数一样使用。

🌸什么是仿函数?

仿函数(functor)是一种行为类似于函数的对象,它可以像函数一样被调用。在C++中,仿函数通常是一个,它重载了函数调用运算符operator(),并且可以像函数一样使用。

仿函数可以被用来封装一些操作或算法,它们可以被传递给其他函数或算法作为参数,或者作为返回值返回给调用者。由于仿函数是一个对象,因此可以在调用它们的过程中保持状态信息,这使得它们可以非常灵活地实现不同的行为。

例如上述的优先级队列又或是库中的sort函数,sort()函数可以接受一个仿函数对象作为第三个参数,这个仿函数对象将被用来比较两个元素的大小关系,这样我们就可以灵活的运用sort函数排序数列为升序或者降序了。

关于仿函数,我们点到为止。

🌸优先级队列的模拟实现

若不了解`堆的结构与使用,可以先看看这篇文章——堆的概念、结构、与实现。

#include <iostream>
#include <vector>
using namespace std;namespace hxy
{// 小于template<class T>class less{public:bool operator()(const T& x, const T& y){return x < y;}};// 大于template<class T>class greater{public:bool operator()(const T& x, const T& y){return x > y;}};// priority_queue类template<class T, class Container = vector<T>,class Compare=less<T>>class priority_queue{// 比较的对象Compare com;// 向上调整void adjust_up(int child){size_t  parent = (child - 1) / 2;while (child > 0){if (com(_con[parent] ,_con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}// 向下调整void adjust_down(int parent){int child = parent * 2 + 1;while (child < _con.size()){// 确保child是两个孩子中大/小的那一个if (child + 1 < _con.size() && com(_con[child], _con[child + 1])){++child;}if (com(_con[parent], _con[child])){swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}public:void push(const T& data){_con.push_back(data);adjust_up(_con.size()-1);}void pop(){// 堆顶元素与堆尾元素互换swap(_con[0],_con[_con.size() - 1]);_con.pop_back();adjust_down(0);}const T& top(){return _con[0];}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:Container _con;};
}

🌷双端队列——deque

stackqueue的模拟实现中,我们使用的是vector 来作为底层容器。但是,在标准库中,都是使用deque来作为底层容器的,那么deque究竟为何能受到青睐呢?

🌸deque的优点与缺点

deque对标的是vector与list,我们可以认为dequevectorlist的结合并且取其精华去其糟粕

🍁vector的优缺点

  • 尾插尾删效率高,头插头删效率低;
  • 支持随机访问;
  • 扩容代价高;

🍁list的优缺点

  • 头删头插效率高;
  • 尾插尾删效率高;
  • 不支持随机访问;
  • 不需要扩容;

🍁deque的优点

  • 头删头插效率高;
  • 尾插尾删效率高;
  • 支持随机访问;
  • 扩容代价低(相比vector);

deque看起来挺不错的,完美的继承了vectorlist的优点。但是,既然deque这么优秀,为什么我们又好像没怎么学习过它呢?答案是,它也有它的缺点。

🍁deque的缺点

  • 中间插入或删除效率低;
  • 没有vectorlist的优点那么极致;

deque的产生就像是什么呢?就例如,我继承了爱因斯坦的高智商,又继承了泰森的力量,但是继承的过程有一些损耗,所以我既没有爱因斯坦极致的智商,又没有泰森极致的力量,我只是个普通人。所以我们说,deque相当于vectorlist的结合产品。

deque看似很中庸,实际用处不大,但是,作为stackqueue的底层容器却又刚好合适,因为栈和队列的性质完美的避开了deque的缺点,只用到了deque的优点——栈和队列只对头部或者尾部进行操作。

🌸deque的原理

对于deque,我们只需要大致认识它的底层结构即可。

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

在这里插入图片描述
deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际deque类似于一个动态的二维数组,其底层结构如下图所示:

在这里插入图片描述
双端队列底层是一段假象的连续空间,实际是分段连续的,为了维护其“整体连续”以及随机访问的假象,落在了deque迭代器身上,因此deque迭代器设计就比较复杂,如下图所示:
在这里插入图片描述

对于deque我们只需做到了解就可以。

在这里插入图片描述
点击下方个人名片,可添加博主的个人QQ,交流会更方便哦~
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓

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

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

相关文章

vue element-ui web端 引入高德地图,并获取经纬度

发版前接到一个临时新需求 &#xff0c;需要在web端地址选择时用地图&#xff0c;并获取经纬度。 临阵发版之际加需求&#xff0c;真的是很头疼&#xff0c;于是赶紧找度娘&#xff0c;找api。 我引入的是高德地图&#xff0c;首先要去申请key &#xff0c; 和密钥&#xff0c;…

20230420使用逻辑分析仪测量摄像头的PAG7920的时钟信号

20230420使用逻辑分析仪测量摄像头的PAG7920的时钟信号 2023/4/20 19:14 在CV1826平台&#xff1a; 1、vsync信号&#xff1a;刷新率120HZ PAG7920LT: Ultra-Low Power Global Shutter Image Sensor Max. Frame Rate 180 FPS 20KSa/20KHZ 2、href行同步信号&#xff1a;KHZ级别…

Vulnhub项目:JANGOW 1.0.1

靶机地址&#xff1a;Jangow: 1.0.1 ~ VulnHub 渗透过程&#xff1a; kali ip&#xff1a;192.168.56.104&#xff0c;使用arp-scan -l查看到靶机ip192.168.56.118 对靶机进行端口探测&#xff0c;发现了21、80端口 访问80端口&#xff0c;发现site目录 点击进去后&#xff0…

【Linux】使用systemd设置开机自启动命令

目录 1 使用使用systemd实现开机自动运行命令1.1 新建一个.service文件1.2 编写.service文件1.2.1 [Unit]1.2.2 [Service]1.2.3 [Install] 1.3 启动服务并设置自启动 2 编写Systemd服务文件的要点2.1 Systemd服务文件的位置2.2 Systemd服务文件的格式2.3 Systemd服务文件的基本…

Spring事务(3)-TransactionInterceptor实际事务执行

Spring事务&#xff08;2&#xff09;-EnableTransactionManagement实现源码解析 中介绍了Spring事务开启和代理的实现&#xff0c;现在了解实际事务执行TransactionInterceptor。 TransactionInterceptor TransactionInterceptor类图 MethodInterceptor&#xff1a;AOP代理后…

IDEA社区版搭建Tomcat服务器并创建web项目

IDEA社区版搭建Tomcat服务器并创建web项目 目标 创建Web项目的目录结构可以启动Tomcat服务器编写Servlet并访问成功 问题 IDEA社区版没有创建Web工程的选项IDEA社区版没有Tomcat插件 实现步骤 针对以上两个问题&#xff0c;分步解决 问题一&#xff1a;IDEA社区版没有创建…

深入认识VirtualPrivateNetwork

目录 一、认识什么是认证&#xff1f; 1.什么是数据认证&#xff0c;有什么作用&#xff0c;有哪些实现的技术手段? 2.什么是身份认证&#xff0c;有什么作用&#xff0c;有哪些实现的技术手段? 二、认识什么是VPN 1.什么VPN技术? 2.VPN技术有哪些分类? 3.IPSEC技术…

我的Qt作品(18)模仿Qt Creator IDE写了一个轻量级的视觉框架

Qt Creator的源码比较庞大。前几年我陆陆续续读过里面的源码。也写了几篇博文&#xff1a; https://blog.csdn.net/libaineu2004/article/details/104728857 https://blog.csdn.net/libaineu2004/article/details/89407333 最近一直想找机会&#xff0c;借用这个IDE的皮&…

mapreduce基础: 手写wordcount案例

文章目录 一、源代码二、运行截图 一、源代码 WordCountMapper类 package org.example.wordcount;import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper;impo…

DNS服务器配置与使用【CentOS】

从本质上说&#xff0c;DNS是一个分布数据库&#xff0c;是一个树形结构&#xff08;不是网状&#xff09;——层次结构 DNS查找过程就是 回溯的过程&#xff08;递归、迭代&#xff09; www.xxx.edu.cn&#xff08;属于四层结构&#xff09; 查询DNS&#xff1a;域名到IP地址的…

【Maven 入门】第二章、Maven核心程序解压与配置

一、Maven 官网地址 首页&#xff1a; Maven – Welcome to Apache Maven(opens new window) 下载页面&#xff1a; Maven – Download Apache Maven(opens new window) 本文以maven-3.3.8为例 具体下载地址&#xff1a;https://dlcdn.apache.org/maven/maven-3/3.8.8/bina…

Linux学习记录—— 이십일 进程间通信(3)信号量和消息队列

文章目录 1、消息队列2、信号量1、了解概念2、信号量理解 3、接口4、理解IPC 1、消息队列 两个进程ab之间系统维护一个队列结构&#xff0c;a进程往队列里放信息&#xff0c;信息编号为1&#xff0c;b进程往队列里放信息&#xff0c;信息编号为2&#xff1b;之后开始读取数据的…

OrCAD原理图检查

OrCAD原理图检查 FPGA或处理器芯片原理图封装检查OrCad元件Part Reference与Reference位号不同检查所有器件是否与CIS库元件匹配用CIS库中的元器件替换已存在器件方法1方法2 DRC检查修改页码Annotate重排位号利用Intersheet References功能进行off-page索引检查封装、厂家、型号…

追梦之旅【数据结构篇】——看看小白试如何利用C语言“痛”撕堆排序

追梦之旅【数据结构篇】——看看小白试如何利用C语言“痛”撕堆排序 ~&#x1f60e; 前言&#x1f64c;堆的应用 —— 堆排序算法&#xff1a;堆排序算法源代码分享运行结果测试截图&#xff1a; 总结撒花&#x1f49e; &#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60…

安装配置 JupyterLab ubuntu20.04

目录 ​编辑 &#xff08;1&#xff09;安装 &#xff08;2&#xff09;配置 &#xff08;1&#xff09;生成配置文件 &#xff08;2&#xff09;生成jupyterlab的登录密码 &#xff08;3&#xff09;修改 jupyter 的配置文件 &#xff08;4&#xff09;安装 jupyterlab…

leetcode每日一题——美团笔试题【1】

今天分享两道算法题&#xff0c;自己刚开始练习&#xff0c;可能在解法上不是最佳的&#xff0c;但是只提供一些自己的思路&#xff0c;欢迎大家多多指教~ 第一题 实现一个算法&#xff0c;确定一个字符串 s 的所有字符是否全都不同。 示例 1&#xff1a;输入: s "lee…

算法的时间复杂度和空间复杂度(2)

计算斐波那契递归Fib的时间复杂度&#xff1f; long long Fib(size_t N) { if(N < 3) return 1; return Fib(N-1) Fib(N-2); } 因为递归先递推后回归&#xff0c;看起来规律像等比数列&#xff0c;也可以用错位相减法&#xff0c;因为斐波那契数列到第二项就不会再计算了&a…

【Spring Boot】SpringBoot设计了哪些可拓展的机制?

文章目录 前言SpringBoot核心源码拓展Initializer拓展监听器ApplicationListenerBeanFactory的后置处理器 & Bean的后置处理器AOP其他的拓展点 前言 当我们引入注册中心的依赖&#xff0c;比如nacos的时候&#xff0c;当我们启动springboot&#xff0c;这个服务就会根据配置…

2023/4/20总结

项目 网上关于listview的资料太少了&#xff0c;在网上的那些资料里面&#xff0c;了解到以下这些。 如果希望listview后期能更改或者更新&#xff0c;那么需要使用到 ObservableList 它可以观察到&#xff0c;listview的改动。 需要特别注意一点的是&#xff1a;写俩者的…

第 三 章 UML 类图

文章目录 前言一、依赖关系&#xff08;虚线箭头&#xff09;二、泛化关系&#xff1a;继承&#xff08;实线空心箭头&#xff09;三、实现关系&#xff08;虚线空心箭头&#xff09;四、关联关系&#xff08;一对一为实线箭头&#xff0c;一对多为实线&#xff09;五、聚合关系…