当前位置: 首页 > news >正文

【C++】STL中优先级队列的使用与模拟实现

前言:在前面我们学习了栈和队列的使用与模拟实现,今天我们来进一步的学习优先级队列使用与模拟实现

💖 博主CSDN主页:卫卫卫的个人主页 💞
👉 专栏分类:高质量C++学习 👈
💯代码仓库:卫卫周大胖的学习日记💫
💪关注博主和博主一起学习!一起努力!
在这里插入图片描述


目录标题

  • 什么是优先级队列
    • 优先级的队列常见功能的使用方式
    • 什么是仿函数
  • 优先级队列的底层实现(适配器版本)
    • 优先级队列的基本框架
      • push():将元素入队列
      • pop():删除队列中优先级最高的元素
      • top():获取并返回队列中优先级最高的元素
      • size():获取并返回队列大小
      • empty():判断队列是否为空
    • 整体代码


什么是优先级队列

C++中的优先级队列是一种特殊的数据结构,它类似于队列,但是元素按照优先级进行排序。在优先级队列中,元素的插入被赋予了一个优先级值,具有较高优先级的元素将排在较低优先级的元素之前(用大白话讲,就是你队列中的元素按照某种要求进行了对应的排序)。

C++中的优先级队列通常使用堆(heap)作为底层实现,可以是最小堆或最大堆。最小堆意味着优先级值较小的元素具有较高的优先级,而最大堆则相反。

优先级队列的主要操作是插入和删除最高优先级的元素。在C++中,可以使用std::priority_queue模板类来实现优先级队列。该模板类提供了一些成员函数,如push()、pop()和top()等,用于插入、删除和获取最高优先级的元素。


优先级的队列常见功能的使用方式

1.插入元素:使用push()函数向优先级队列插入元素(调用前需要导入头文件queue)

int main()
{priority_queue<int> s1;//创建一个对象s1.push(10);//入队列,且队列中的元素会默认按照降序进行排序s1.push(20);s1.push(0);s1.push(9);s1.push(120);return 0;
}

  1. 删除最高优先级元素:使用pop()函数删除优先级队列中的最高优先级元素(可以理解成删除队列中排序过后的队头的元素)。
int main()
{priority_queue<int> s1;s1.push(10);//入队列s1.push(120);s1.pop();//删除队头的元素return 0;
}

  1. 获取最高优先级元素:使用top()函数获取优先级队列中的最高优先级元素(通俗的理解获取队列排序过后的队头元素)。
int main()
{priority_queue<int> s1;s1.push(10);//入队列s1.push(9);s1.push(120);s1.pop();//出队列auto num = s1.top();//获取队列的队头的元素cout << num << endl;return 0;
}
//运行结果:10

  1. 获取队列中的元素数量:使用size()函数获取优先级队列中的元素数量。
int main()
{priority_queue<int> s1;s1.push(10);//入队列cout << s1.size() << endl;//输出队列中元素的个数return 0;
}

  1. 判断队列是否为空:使用empty()函数判断优先级队列是否为空。
int main()
{priority_queue<int> s1;s1.push(10);s1.push(20);s1.push(0);s1.push(9);s1.push(120);auto num = s1.top();cout << num << endl;cout << s1.size() << endl;if (!s1.empty())//判断队列是否有元素{cout << "队列中有元素" << endl;}else cout << "队列中没有元素" << endl;return 0;
}

需要注意的是,std::priority_queue默认以降序排序,即最大元素具有最高优先级。如果希望以升序排序,则可以使用自定义的比较函数或者使用std::greater作为模板参数

// 使用自定义的比较函数,greater即默认升序的排序方式,也可以调用自己写的排序方式
std::priority_queue<int, std::vector<int>, std::greater<int>> pq;// 或者使用std::greater模板参数
std::priority_queue<int, std::vector<int>, std::greater<>> pq;


什么是仿函数

C++中的仿函数是一个类或者结构体,实现了函数调用操作符(operator())的重载。通过重载函数调用操作符,可以使得仿函数对象像函数一样被调用。仿函数常用于算法中,用于实现特定的操作或者运算。它可以接受一个或多个参数,并返回一个结果。通过仿函数,可以实现函数对象的状态的维护,以及在算法中对元素进行处理的定制化操作。
例子:

template <class T>
class less//通过类来判断他的大小
{
public:operator() (const T& x, const T& y){return x < y;}
};template <class T>
class greater//同理
{
public:operator() (const T& x, const T& y){return x > y;}
};int main()
{int num1 = 10, num2 = 20,num3 = 30,num4 = 50;less<int> s1;greater<int> s2;if (s1(num1, num2))//s1()就类似与之前的一个函数的样子,我们调用s1这个对象即可完成你想要指定的操作{cout << "num1 < num2" << endl;}if (s2(num4, num3))//同理你调用s2也可以类似于函数的感觉,去完成你想要指定完成的操作{cout << "num4 > num3" << endl;}return 0;
}

优先级队列的底层实现(适配器版本)

前言:这里我们需要先知道刚刚我们使用了那些功能,这里方便我们对其进行模拟实现。
基本操作:
1、push():将元素入队列。【将元素入队列,并且让其按照升序或者降序进行某种方式进行排序】

2、pop():删除队列中优先级最高的元素。【队首出队列,并且依然要保持队列的完整性】

3、top():获取并返回队列中优先级最高的元素。

4、size():获取并返回队列大小。【返回值为 unsigned int(size_t)类型】

5、empty():判断队列是否为空。【返回值为bool类型。队列为空返回true,不空返回false】


优先级队列的基本框架

namespace bit
{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;}};template <class T, class Container = vector<T>, class Compare = less<T>>//默认是大堆,借助适配器帮助实现class  priority_queue//基本类{public:private:Container _con;//调用适配器}
}

push():将元素入队列

代码思路:我们的适配器默认调用的是vector因为他内部的接口可以调用尾插,同理我们这里直接调用尾插的函数即可,但是我们提到过这个是一个优先级队列,优先级队列的底层就是一个,那么我们对堆插入元素的时候在数据结构讲过我们需要对其进行调整,否则这个堆就会失去他原有的完整性,如果对堆这块内容不太熟悉的小伙伴可以去看看我之前的博客堆的模拟实现

void push(const T& x)//入队列
{_con.push_back(x);//需要保证队列里面的优先级的顺序,因此我们需要对其进行向上调整adjust_up(_con.size() - 1);//当前的元素个数减一就是当前孩子结点下标,然后将他向上调整即可完成插入
}//向上调整
void adjust_up(size_t child)//插入的是孩子看孩子是否比父亲还大,比父亲还大就交换,且是默认大堆
{Compare com;int parent = (child - 1) / 2;//父亲结点的下标while (child > 0){//巧妙的利用仿函数对其进行默认的降序进行排序,也可以通过传great进行升序排序if (com(_con[parent], _con[child]))//比父亲大就交换{swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;//孩子不比父亲大,说明就是当前的位置}}
}

pop():删除队列中优先级最高的元素

代码思路:在之前讲解堆的时候我们知道,要想删除堆顶的元素,我们通常的做法是将堆顶的元素和尾元素进行交换,然后在删除此时堆尾部的元素,进行删除,然后在将交换后的堆顶的元素向下调整保持堆的完整性,因此我们在优先级队列中需要用到同样的做法,将队首和队尾的元素进行交换,然后删除队尾的元素,然后向下调整即可。

void pop()//队头出队列
{swap(_con[0], _con[_con.size() - 1]);//将堆的底部元素和堆顶的交换,然后删除堆底部元素就完成了队头出队列_con.pop_back();//删除堆顶元素adjust_down(0);//向下调整交换过后的堆,即依然保持堆的完整性
}void adjust_down(size_t parent)//向下调整
{Compare com;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[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}
}

top():获取并返回队列中优先级最高的元素

代码思路:我们知道优先级队列的底层就是个堆,队首的那个元素就是堆顶的元素,因此直接返回下标为0的首元素即可。

const T& top()//获取队首元素
{return _con[0];
}

size():获取并返回队列大小

代码思路:这里我们直接调用容器中的函数即可

size_t size()//查看队列中元素的个数
{return _con.size();
}

empty():判断队列是否为空

代码思路:同理调用容器中的函数即可。

bool empty()//判断是否为空,依然玩适配器的那套玩法
{return _con.empty();
}

整体代码

#include <iostream>
#include<vector>
#include<assert.h>
using namespace std;namespace bit
{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;}};template <class T, class Container = vector<T>, class Compare = less<T>>//默认是大堆class priority_queue{public:void adjust_up(size_t child)//插入的是孩子看孩子是否比父亲还大,比父亲还大就交换,且是默认大堆{Compare com;int 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 push(const T& x)//入队列{_con.push_back(x);adjust_up(_con.size() - 1);//vector的元素个数减一就是当前孩子结点下标,然后将他向上调整即可完成插入}void adjust_down(size_t parent)//向下调整{Compare com;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[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}void pop()//队头出队列{swap(_con[0], _con[_con.size() - 1]);//将堆的底部元素和堆顶的交换,然后删除堆底部元素就完成了队头出队列_con.pop_back();//删除堆顶元素adjust_down(0);//向下调整交换过后的堆,即依然保持堆的完整性}bool empty()//判断是否为空,依然玩适配器的那套玩法{return _con.empty();}size_t size()//查看队列中元素的个数{return _con.size();}const T& top()//获取队首元素{return _con[0];}private:Container _con;};void test1(){bit::priority_queue<int, vector<int>, bit::greater<int>> pq;pq.push(2);pq.push(1);pq.push(4);pq.push(3);pq.push(7);pq.push(8);while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;}void test2(){priority_queue<int> pq;//默认大堆pq.push(2);pq.push(1);pq.push(4);pq.push(3);pq.push(7);pq.push(8);while (pq.size()){cout << pq.top() << " ";pq.pop();}cout << endl;}
}emplate <class T>
class less
{
public:operator() (const T& x, const T& y){return x < y;}
};template <class T>
class greater
{
public:operator() (const T& x, const T& y){return x > y;}
};int main()
{int num1 = 10, num2 = 20,num3 = 30,num4 = 50;less<int> s1;greater<int> s2;if (s1(num1, num2)){cout << "num1 < num2" << endl;}if (s2(num4, num3)){cout << "num4 > num3" << endl;}return 0;
}//int main()
//{
//	//bit::test1();
//	//bit::test2();
//	return 0;
//}

好啦,今天的内容就到这里啦,下期内容预告C++中的模板大全解.


结语:前段时间博主又又又去忙学校的事情和一些比赛啥的,这段时间会猛猛干的!。


🌏🗺️ 这里祝各位接下来的每一天好运连连 💞💞

相关文章:

【C++】STL中优先级队列的使用与模拟实现

前言&#xff1a;在前面我们学习了栈和队列的使用与模拟实现&#xff0c;今天我们来进一步的学习优先级队列使用与模拟实现 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏分类:高质量&#xff23;学习 &#x1f448; &#x1f4af;代码仓库:卫…...

C#开发-集合使用和技巧(二)Lambda 表达式介绍和应用

C#开发-集合使用和技巧 Lambda 表达式介绍和应用 C#开发-集合使用和技巧介绍简单的示例&#xff1a;集合查询示例&#xff1a; 1. 基本语法从主体语句上区分&#xff1a;1. 主体为单一表达式2. 主体是代码块&#xff08;多个表达式语句&#xff09; 从参数上区分1. 带输入参数的…...

Qt底层原理:深入解析QWidget的绘制技术细节(2)

&#xff08;本文续上一篇《Qt底层原理&#xff1a;深入解析QWidget的绘制技术细节(1)》&#xff09; QWidget绘制体系为什么这么设计【重点】 在传统的C图形界面框架中&#xff0c;例如DUILib等&#xff0c;控件的绘制逻辑往往直接在控件的类的内部&#xff0c;例如PushButt…...

【Gradio】表格数据科学与图表-连接到数据库

简介 本指南解释了如何使用 Gradio 将您的应用程序连接到数据库。我们将连接到托管在 AWS 上的 PostgreSQL 数据库&#xff0c;但 gradio 对您连接到的数据库类型及其托管位置完全不可知。因此&#xff0c;只要您能够编写 Python 代码来连接到您的数据&#xff0c;您就可以使用…...

艾多美用“艾”为生命加油,献血活动回顾

用艾为生命加油 6月10日~16日&#xff0c;艾多美中国开启献血周活动&#xff0c;已经陆续收到来自烟台总部、山东、广东、河南、四川、重庆、贵阳&#xff0c;乌鲁木齐&#xff0c;吉林&#xff0c;等地区的艾多美员工、会员、经销商发来的爱心助力&#xff0c;截止到目前&…...

人工智能在气象预报领域的崛起:GraphCast引领新纪元

最近&#xff0c;谷歌推出的天气预测大模型GraphCast在全球范围内引起了广泛关注&#xff0c;其卓越的表现不仅刷新了人们对AI能力的认知&#xff0c;更预示着传统天气预报工作模式的深刻变革。 GraphCast是一款基于机器学习技术的天气预测工具&#xff0c;它通过深度学习和大数…...

http和https的区别在哪

HTTP&#xff08;超文本传输协议&#xff09;和HTTPS&#xff08;超文本传输安全协议&#xff09;之间存在几个关键区别主要涉及安全性、端口、成本、加密方式、搜索引擎优化&#xff08;SEO&#xff09;、身份验证等方面 1、安全性&#xff1a;HTTP&#xff08;超文本传输协议…...

windows10远程桌面端口,Windows 10远程桌面端口修改的两个方法

在Windows 10系统中&#xff0c;远程桌面功能允许用户通过网络从一台计算机远程访问和控制另一台计算机。默认情况下&#xff0c;远程桌面服务使用的端口是3389。然而&#xff0c;出于安全考虑&#xff0c;许多管理员和用户希望修改这一默认端口。本指南将详细介绍如何在Window…...

力扣1504.统计全1子矩形

力扣1504.统计全1子矩形 开一个二维数组存每个点从它本身开始向左有多少连续的1 遍历矩形右下角(i,j) 再遍历行k in i每一行的矩形数量 minx min(minx,left(k,j)) class Solution {public:int numSubmat(vector<vector<int>>& mat) {int n mat.size();int…...

vue3高德地图组件化,解决复用地图组件时渲染失败问题

思路&#xff1a;多个页面都需要调用地图&#xff0c;将地图封装成一个组件进行复用&#xff0c;发现调用时只有第一次渲染成功了。 解决&#xff1a;相同 id 的地图渲染只能有一次&#xff0c;如果多个复用地图的页面不需要同时渲染&#xff0c;使用 v-if 来控制&#xff1b;…...

Langchain 如何工作

How does LangChain work? LangChain是如何工作的? Let’s consider our initial example where we upload the US Constitution PDF and pose questions to it. In this scenario, LangChain compiles the data from the PDF and organizes it. 让我们考虑我们最初的例子…...

【数据结构】顺序表实操——通讯录项目

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…...

C++继承与多态—多重继承的那些坑该怎么填

课程总目录 文章目录 一、虚基类和虚继承二、菱形继承的问题 一、虚基类和虚继承 虚基类&#xff1a;被虚继承的类&#xff0c;就称为虚基类 virtual作用&#xff1a; virtual修饰成员方法是虚函数可以修饰继承方式&#xff0c;是虚继承&#xff0c;被虚继承的类就称为虚基类…...

论文阅读:基于谱分析的全新早停策略

来自JMLR的一篇论文&#xff0c;https://www.jmlr.org/papers/volume24/21-1441/21-1441.pdf 这篇文章试图通过分析模型权重矩阵的频谱来解释模型&#xff0c;并在此基础上提出了一种用于早停的频谱标准。 1&#xff0c;分类难度对权重矩阵谱的影响 1.1 相关研究 在最近针对…...

1.接口测试-postman学习

目录 1.接口相关概念2.接口测试流程3.postman基本使用-创建请求&#xff08;1&#xff09;环境&#xff08;2&#xff09;新建项目集合Collections&#xff08;3&#xff09;新建collection&#xff08;4&#xff09;新建模块&#xff08;5&#xff09;构建请求请求URLheader设…...

2024年码蹄杯本科院校赛道初赛(省赛)

赛时所写题&#xff0c;简单写一下思路&#xff0c;qwq 第一题&#xff1a; 输出严格次小值&#xff0c; //#pragma GCC optimize(2)#include <iostream> #include <cstring> #include <algorithm> #include <vector> #include <queue> #incl…...

PHP蜜语翻译器在线文字转码解码源码

源码介绍 PHP蜜语翻译器在线文字转码解码源码 文字加密通话、一键转换、蜜语密码 无需数据库,可以将文字、字母、数字、代码、表情、标点符号等内容转换成新的文字形式&#xff0c;通过简单的文字以不同的排列顺序来表达不同的内容&#xff01;支持在线加密解密 有多种加密展示…...

安卓浏览器区分启动、打开、分享

搞了几个钟头&#xff0c;终于全兼容了&#xff0c;分享有2种类型&#xff01; void getDataFromIntent(Intent intent) {if (intent.getAction().equals(Intent.ACTION_VIEW)) {urln intent.getDataString();if (urln ! null) {if (urln.contains("\n"))urln url…...

C/C++ 数组负数下标

一 概述 在 C 中&#xff0c;数组是一块连续的内存空间&#xff0c;数组的下标通常用来定位这段内存中的特定元素。下标通常从 0 开始&#xff0c;最大到数组长度减 1。例如&#xff0c;一个有 10 个元素的数组&#xff0c;其有效下标范围是从 0 到 9。 当你尝试使用负数下标来…...

钓鱼网站开发原理(社会工程学)

钓鱼网站开发原理&#xff08;社会工程学&#xff09; 一、课程简介1、课程大纲2、课程目标3、知识储备 二、钓鱼网站简介1、什么是钓鱼网站2、开发&原理 三、PHP环境搭建1、简介2、自动安装MySQL/apache/PHP3、安装navicat 四、PDO表单入库案例1、语法2、显示登录表单3、入…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

Kafka主题运维全指南:从基础配置到故障处理

#作者&#xff1a;张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1&#xff1a;主题删除失败。常见错误2&#xff1a;__consumer_offsets占用太多的磁盘。 主题日常管理 …...

Linux 下 DMA 内存映射浅析

序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存&#xff0c;但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程&#xff0c;可以参考这篇文章&#xff0c;我觉得写的非常…...

【深尚想】TPS54618CQRTERQ1汽车级同步降压转换器电源芯片全面解析

1. 元器件定义与技术特点 TPS54618CQRTERQ1 是德州仪器&#xff08;TI&#xff09;推出的一款 汽车级同步降压转换器&#xff08;DC-DC开关稳压器&#xff09;&#xff0c;属于高性能电源管理芯片。核心特性包括&#xff1a; 输入电压范围&#xff1a;2.95V–6V&#xff0c;输…...

起重机起升机构的安全装置有哪些?

起重机起升机构的安全装置是保障吊装作业安全的关键部件&#xff0c;主要用于防止超载、失控、断绳等危险情况。以下是常见的安全装置及其功能和原理&#xff1a; 一、超载保护装置&#xff08;核心安全装置&#xff09; 1. 起重量限制器 功能&#xff1a;实时监测起升载荷&a…...