[C++]优先级队列
1 .了解优先级队列

优先级队列是一种容器适配器,根据一些严格的弱排序标准,专门设计使其第一个元素始终是它所包含的元素中最大的元素。
此上下文类似于堆,其中可以随时插入元素,并且只能检索最大堆元素(优先级队列中顶部的元素)。
优先级队列是作为容器适配器实现的,容器适配器是使用特定容器类的封装对象作为其底层容器的类,提供一组特定的成员函数来访问其元素。元素是从特定容器的“背面”弹出的,该容器称为优先级队列的顶部。
基础容器可以是任何标准容器类模板,也可以是其他一些专门设计的容器类。容器应通过随机访问迭代器访问,并支持以下操作:
- empty()
- size()
- front()
- push_back()
- pop_back()
标准容器类并满足这些要求。默认情况下,如果未为特定类实例指定容器类,则使用标准容器。
需要支持随机访问迭代器,以便始终在内部保持堆结构。这是由容器适配器通过自动调用算法函数自动完成的,并在需要时自动完成。vector、deque、priority_queue、vector、make_heappush_heap、pop_heap
2.优先级队列的相关接口
优先级队列的接口有如下几种。对于优先级队列我们默认是它的大的数优先级高。其底层是一个堆。也就是说,我们默认是大堆,所以大的数优先级高。如果是一个小堆,那么就是小的优先级高
1.常用接口函数

我们来随便使用一下这些接口吧:
#include<iostream>
#include<vector>
#include<queue>
using namespace std;void test_priority_queue()
{priority_queue<int> pq;pq.push(123);pq.push(1045);pq.push(2);pq.push(3);pq.push(4);while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;
}int main()
{test_priority_queue();
}
运行结果:

可以看到,默认是一个大堆,但是我们会注意到,它库里面默认传的是less,但是却是一个大堆,这里需要额外注意一下。

如果想要是一个小堆的话,我们需要将这个less替换为greater:
#include<iostream>
#include<vector>
#include<queue>
using namespace std;void test_priority_queue()
{priority_queue<int,vector<int>,greater<int>> pq;pq.push(123);pq.push(1045);pq.push(2);pq.push(3);pq.push(4);while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;
}int main()
{test_priority_queue();
}
运行结果:

在这里我们传的less,greater这些也称之为仿函数。也就是说,通过仿函数控制实现大小堆.除此之外,这里除了可以传vector以外,还可以传递deque,但是由于堆需要大量访问[]运算符,所以deque的效率不高。
2.构造函数
如下所示,可以无参构造,也可以用迭代器区间进行初始化。

3.优先队列的模拟实现
优先级队列,主要还是堆的逻辑的实现。即堆的构造,向上调整和向下调整。
这些我们在数据结构讲过了,我直接上源码了
template<class T, class Container = vector<T>>class priority_queue{private:void AdjustDown(int parent){int child = parent * 2 + 1;while (child<_con.size()){if (child + 1 < _con.size() && _con[child] < _con[child + 1]){child++;}if (_con[child] > _con[parent]){swap(_con[child], _con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}void AdjustUp(int child){int parent = (child - 1) / 2;while (child > 0){if (_con[child] > _con[parent]){swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}public:template<class InputIterator>priority_queue(InputIterator first, InputIterator last){while (first != last){_con.push_back(*first);first++;}for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--){AdjustDown(i);}}priority_queue(){}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);}void push(const T& val){_con.push_back(val);AdjustUp(_con.size() - 1);}const T& top(){return _con[0];}bool empty(){return _con.empty();}size_t size(){return _con.size();}private:Container _con;};
既然这些容器都学完了,这里附上我的一道错题:
假设cont是一个Container 的示例,里面包含数个元素,那么当CONTAINER为:
1.vector 2.list 3.deque 会导致下面的代码片段崩溃的Container 类型是( )
int main()
{
Container cont = { 1, 2, 3, 4, 5};
Container::iterator iter, tempIt;
for (iter = cont.begin(); iter != cont.end();)
{
tempIt = iter;
++iter;
cont.erase(tempIt);
}
}
A.1, 2
B.2, 3
C.1, 3
D.1, 2, 3
答案选择C
解析:
各个容器的erase(pos)实现:
1. vector,erase(pos),直接把pos+1到finish的数据拷贝到以pos为起点的区间上,也就是vector的长度会逐渐变短,同时iter会逐渐往后移动,直到iter == cont.end(),由于容器中end()返回的迭代器是最后一个元素的下一个(这个地方没有任何值),现在考虑这个状态前一个状态,此时要删除的点是iter, tempIt = iter, ++iter会指向此时的end(),但是执行erase(tempIt)之后,end()向前移动了!!!问题来了,此时iter空了!!!不崩溃才怪。
2. list,erase(pos),干的事情很简单,删除自己,前后的节点连接起来就完了,所以iter自增的过程不会指空,不会崩溃喽。
3.deque,erase(pos),与vector的erase(pos)有些类似,基于结构的不同导致中间有些步骤不太一致。先说说deque的结构(这个结构本身比较复杂,拣重要说吧,具体看STL源码),它是一个双向开口的连续线性空间,实质是分段连续的,由中控器map维持其整体连续的假象。其实题中只要知道它是双向开口的就够了(可以在头部或尾部增加、删除)。在题中有erase(pos),deque是这样处理的:如果pos之前的元素个数比较少,那么把start到pos-1的数据移到起始地址为start+1的区间内;否则把pos后面的数据移到起始地址为pos的区间内。在题中iter一直往后移动,总会出现后面数据比前面少的时候,这时候问题就和1一样了,必须崩溃!
解析思路来源:会导致上面的代码片段崩溃的CONTAINER类型是?_完美世界笔试题_牛客网
来源:牛客网
4.仿函数
1.仿函数介绍
我们知道对于优先级队列可以用仿函数改变其是大堆还是小堆。根据底层逻辑可知,仿函数应该就是改变了大小比较。才改变的行为。我们可以写一个简单的仿函数类
如下所示就是一个最简单的仿函数
class less{public:bool operator()(int x, int y){return x < y;}};
这样我们就可以类似于一个函数一样进行比较大小了,仿函数即函数对象,可以让类对象像函数一样使用
有了仿函数,我们就可以在前面的优先级队列中使用仿函数来切换大堆小堆了。在C语言中,我们想要实现这个功能只有使用函数指针。而这个仿函数就刚好可以替换掉函数指针。因为函数指针的弊端太明显了,它太过于复杂了,可读性不好。
2.优先级队列添加仿函数
template<class T, class Container = vector<T>, class Compare = less<T>>class priority_queue{private:void AdjustDown(int parent){Compare com;int 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 AdjustUp(int child){Compare com;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;}}}public:template<class InputIterator>priority_queue(InputIterator first, InputIterator last){while (first != last){_con.push_back(*first);first++;}for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--){AdjustDown(i);}}priority_queue(){}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);}void push(const T& val){_con.push_back(val);AdjustUp(_con.size() - 1);}const T& top(){return _con[0];}bool empty(){return _con.empty();}size_t size(){return _con.size();}private:Container _con;};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;}};
3.需要自己写仿函数的情形
我们的上面的仿函数是模拟库里面的行为,上面的仿函数在库里面早已给出,我们无需自己动手写。但是有时候我们也需要自己去写一个仿函数。
如我们存储的是一个指针,而不是一个对象,等情况
struct LessTime
{bool operator()(Time* x, Time* y){return *x < *y;}
};
5.优先级队列完整代码
template<class T, class Container = vector<T>, class Compare = less<T>>class priority_queue{private:void AdjustDown(int parent){Compare com;int 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 AdjustUp(int child){Compare com;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;}}}public:template<class InputIterator>priority_queue(InputIterator first, InputIterator last){while (first != last){_con.push_back(*first);first++;}for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--){AdjustDown(i);}}priority_queue(){}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();AdjustDown(0);}void push(const T& val){_con.push_back(val);AdjustUp(_con.size() - 1);}const T& top(){return _con[0];}bool empty(){return _con.empty();}size_t size(){return _con.size();}private:Container _con;};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;}};
相关文章:
[C++]优先级队列
1 .了解优先级队列 优先级队列是一种容器适配器,根据一些严格的弱排序标准,专门设计使其第一个元素始终是它所包含的元素中最大的元素。 此上下文类似于堆,其中可以随时插入元素,并且只能检索最大堆元素(优先级队列中顶…...
学习大数据DAY22 Linux 基 本 指 令 3与 在 Linux 系 统 中 配 置MySQL 和 Oracle
目录 网络配置类 ps 显示系统执行的进程 kill systemctl 服务管理 配置静态 ip 常见错误---虚拟机重启网卡失败或者网卡丢失 mysql 操作 上机练习 6---安装 mysql---参考《mysql 安装》文档 解锁 scott 重启后的步骤 上机练习 7---安装 oracle---参考《oracle 安装》…...
scp 服务器复制命令
步骤如下: 终端执行如下命令 #ssh-keygen -t rsa 2. 密钥生成后会在 /root/.ssh/ 文件夹下产生两个文件 id_rsa id_rsa.pub 将 id_rsa.pub 文件复制到 152.136.121.24 执行如下命令 scp /root/.ssh/id_rsa.pub root152.136.121.24:/root/.ssh/authorized_keys…...
PyQt5学习路线
后续会根据该文章的路线逐步发布对应的教程,订阅专栏不迷路🥰 本专栏纯干货🤩 学习Python的PyQt5库,可以遵循以下的学习路线: 1. Python基础 掌握Python语法:确保你熟悉Python的基本语法,包括…...
2024论文精读:利用大语言模型(GPT)增强上下文学习去做关系抽取任务
文章目录 1. 前置知识2. 文章通过什么来引出他要解决的问题3. 作者通过什么提出RE任务存在上面所提出的那几个问题3.1 问题一:ICL检索到的**示范**中实体个关系的相关性很低。3.2 问题二:示范中缺乏解释输入-标签映射导致ICL效果不佳。 4. 作者为了解决上…...
WEB 手柄 http通信,mcu端解析代码 2024/7/23 日志
WEB 手柄 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>WEB遥控器</title> </head> &l…...
cmake中的正则表达式
以下字符或者字符组合在cmake的正则表达式中的特殊含义: ^ 匹配输入的开始 $ 匹配输入的结束 . 匹配任意一个字符 \<char> 匹配一个字符,如.匹配字符.,\匹配字符\,\a匹配字符a [ ] 匹配在括号里面的任意字符࿰…...
05. Java 三大范式
1. 前言 在面向对象语言中涉及到诸多的设计模式,例如单例模式、适配器模式,设计模式的存在是为了让系统中的代码逻辑更加清晰,帮助开发者建立更加健壮的系统,同时满足易修改特性和易扩展特性。数据库设计时也存在类似设计模式的通…...
opencv 按键开启连续截图,并加载提示图片
背景图小图 键盘监听使用的是pynput 库 保存图片时使用了年月日时分秒命名 原图: from pynput import keyboard import cv2 import time# 键盘监听 def on_press(key):global jieglobal guanif key.char a:jie Trueelif key.char d:jie Falseelif key.char…...
Android-- 集成谷歌地图
引言 项目需求需要在谷歌地图: 地图展示,设备点聚合,设备站点,绘制点和区域等功能。 我只针对我涉及到的技术做一下总结,希望能帮到开始接触谷歌地图的伙伴们。 集成步骤 1、在项目的modle的build.gradle中添加依赖如…...
Jvm是如何处理异常的
异常抛出 当Java程序运行时遇到无法处理的情况时,会抛出一个异常(比如在一个方法中如果发生异常),这时会创建一个异常对象,并转交给JVM,该异常对象包含异常名称,异常描述以及异常发生时应用程序的状态。创建异常对象并转交给JVM的过程称为抛出异常。 异常捕捉 当JVM检测…...
recursion depth exceeded” error
有些时候不可以用jax.jit装饰器 参考资料:使用 JAX 后端在 Keras 3 中训练 GAN |由 Khawaja Abaid |中等 (medium.com)...
虚拟现实和增强现实技术系列—Expressive Talking Avatars
文章目录 1. 概述2. 背景介绍3. 数据集3.1 设计标准3.2 数据采集 4. 方法4.1 概述4.2 架构4.3 目标函数 5. 实验评测5.1 用户研究5.2 我们方法的结果5.3 比较与消融研究 1. 概述 支持远程协作者之间的交互和沟通。然而,明确的表达是出了名的难以创建,主…...
网站验证:确保网络安全与信任的重要步骤
网站验证:确保网络安全与信任的重要步骤 引言 在数字时代,网站验证是确保网络安全和建立用户信任的关键措施。随着网络诈骗和恶意软件的日益增多,验证网站的真实性和安全性变得尤为重要。本文将探讨网站验证的重要性、常见的验证方法以及如…...
C语言——字符串比较函数strcmp和strncmp
目录 strcmp 函数原型如下: 示例 注意事项 strcmp自实现代码: strncmp 函数 函数原型: 参数: 返回值: 特点: 两者之间的区别和联系 strcmp strcmp 是 C 语言标准库中的一个函数,用于…...
redis的集群模式
目录 1. 为什么使用redis集群 2. 主从模式 2.1修改配置文件 2.2 开启三台redis服务 2.3配置主从关系 3. 哨兵模式 3.1 监控功能 3.2 选举的机制 3.3 准备条件 4. 去中心化模式 4.1 准备三主三从 4.2 启动redis 4.3 分配槽以及主从关系 4.4 命令行的客户端 redis提供…...
基于微信小程序+SpringBoot+Vue的青少年科普教学系统平台(带1w+文档)
基于微信小程序SpringBootVue的青少年科普教学系统平台(带1w文档) 基于微信小程序SpringBootVue的青少年科普教学系统平台(带1w文档) 这个工具就是解决上述问题的最好的解决方案。它不仅可以实时完成信息处理,还缩短高校教师成果信息管理流程,使其系统化…...
智能听觉:从任务特定的机器学习到基础模型
关键词:计算机听觉、音频基础模型、多模态学习、声音事件检测 声音无处不在,弥漫于我们生活的每一个角落。鸟儿向伴侣倾诉心意的歌声,浓缩咖啡机中蒸汽的嘶嘶作响,午后阳光下昆虫振翅的嗡嗡声,金属屋顶上雨滴跳跃的滴答…...
14、如何⽤DDD设计微服务代码模型
在完成领域模型设计后,接下来我们就可以开始微服务的设计和 落地了。在微服务落地前,⾸先要确定微服务的代码结构,也就是我 下⾯要讲的微服务代码模型。 只有建⽴了标准的微服务代码模型和代码规范后,我们才可以将 领域对象映射到…...
ArcGIS Pro SDK (九)几何 12 多面体
ArcGIS Pro SDK (九)几何 12 多面体 文章目录 ArcGIS Pro SDK (九)几何 12 多面体1 通过拉伸多边形或折线构建多面体2 多面体属性3 构建多面体4 通过MultipatchBuilderEx构建多面体5 从另一个多面体构建多面体6 从 3D 模型文件构建…...
OpenClaw日志分析:Qwen3-32B每日自动汇总服务器异常事件
OpenClaw日志分析:Qwen3-32B每日自动汇总服务器异常事件 1. 为什么需要自动化日志分析 作为一名运维工程师,我每天早晨的第一项工作就是检查服务器日志。Nginx的错误日志、系统内核日志、应用服务的异常输出……这些文件分散在不同的目录,格…...
深入排查k8s集群6443端口连接拒绝:从kubectl故障到系统级修复
1. 当kubectl突然罢工:6443端口连接拒绝的紧急处理 那天早上我像往常一样打开终端,准备用kubectl get pods查看集群状态,结果终端冷冰冰地抛出一行错误:"Unable to connect to the server: dial tcp 192.168.1.1:6443: conne…...
SD卡 vs SD NAND:SPI模式下性能对比与选型建议(含实测数据)
SD卡 vs SD NAND:SPI模式下性能对比与选型建议(含实测数据) 在智能硬件和消费电子产品的开发过程中,存储方案的选择往往成为硬件工程师面临的关键决策之一。面对市场上琳琅满目的存储器件,如何在性能、成本和可靠性之…...
DICOM RT Structure深度解析——从文件结构到靶区可视化
1. DICOM RT Structure文件基础认知 第一次接触DICOM RT Structure文件时,我完全被那些密密麻麻的标签和序列搞晕了。这就像拿到一份没有目录的医学百科全书,所有内容都堆在一起。但经过几个项目的实战,我发现只要抓住三个核心序列࿰…...
Nextcloud Android文件同步革命:实现跨设备无缝数据访问的完整指南 [特殊字符]
Nextcloud Android文件同步革命:实现跨设备无缝数据访问的完整指南 📱 【免费下载链接】android 📱 Nextcloud Android app 项目地址: https://gitcode.com/gh_mirrors/andr/android Nextcloud Android应用是一款功能强大的开源云存储…...
突破网盘下载限制:直链解析工具的技术实现与应用指南
突破网盘下载限制:直链解析工具的技术实现与应用指南 【免费下载链接】Online-disk-direct-link-download-assistant 可以获取网盘文件真实下载地址。基于【网盘直链下载助手】修改(改自6.1.4版本) ,自用,去推广&#…...
【开题答辩全过程】以 校园超市购物系统为例,包含答辩的问题和答案
个人简介一名14年经验的资深毕设内行人,语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…...
OpenClaw三种方式安装:手把手保姆级教程
前置操作 【一】获取API Key 现在很多平台的API Key都有免费额度,阿里云和Kimi的优惠力度大些,大家按需索取。 阿里云百炼 Step01:注册/登录阿里云 Step02:创建并获取API Key 注意:我们要的是API Key,如…...
VibeVoice语音合成实战:流式播放+音频下载,打造个性化语音播报系统
VibeVoice语音合成实战:流式播放音频下载,打造个性化语音播报系统 1. 项目概述 VibeVoice-Realtime是微软开源的一款轻量级实时语音合成(TTS)模型,专为需要即时语音反馈的场景设计。这个只有0.5B参数的模型,却能在300毫秒内开始…...
Windows远程桌面多用户协作解决方案:从原理到实践
Windows远程桌面多用户协作解决方案:从原理到实践 【免费下载链接】rdpwrap.ini RDPWrap.ini for RDP Wrapper Library by StasM 项目地址: https://gitcode.com/GitHub_Trending/rd/rdpwrap.ini 问题溯源:远程协作的瓶颈与突破 当团队成员需要同…...
