当前位置: 首页 > 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、入…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区&#xff08;Partitioning&#xff09;是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分&#xff08;分区&#xff09;可以独立存储、管理和优化&#xff0c;…...

学习一下用鸿蒙​​DevEco Studio HarmonyOS5实现百度地图

在鸿蒙&#xff08;HarmonyOS5&#xff09;中集成百度地图&#xff0c;可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API&#xff0c;可以构建跨设备的定位、导航和地图展示功能。 ​​1. 鸿蒙环境准备​​ ​​开发工具​​&#xff1a;下载安装 ​​De…...