C++STL---priority_queue知识总结及模拟实现

前言

和stack与queue一样,priority_queue也是一种容器适配器。

他的本质其实是堆,作优先级队列的底层需要能够通过随机迭代器访问,所以他的底层是可以由vector和queue实例化,默认情况下priority_queue默认是用vector作为底层实例化,此外我们还可以特指定deque作为他的底层进行实例化。

需要支持随即迭代器,是因为要始终维持堆,优先级队列的本质就是堆。容器适配器通过在需要时自动调用算法函数make_heap,push_heap,pop_heap来始终维持堆。

priority_queue默认是大堆。

priority_queue的使用

priority_queue定义方式

优先级队列有三个模板参数,第一个是元素种类,第二个是用来构造优先级队列的底层容器种类,第三个是构建的方式(大堆还是小堆)。

//这种是不指定底层容器和构造方式的构建,默认底层是vector,构建大堆
priority_queue<int> pq;//这种指定了底层容器和构造方式,我这里设置的底层是deque<int>,构建的是小堆
priority_queue<int,deque<int>,greater<int>> pq1;//我们这里如果要是想要选择构建大堆还是小堆的时候,就只能必须把底层容器的类型也给了
//这是设置缺省参数时的规定,这里不赘述

priority_queue的接口介绍

成员函数功能
push元素入队,通过push_heap函数使其移向堆中适当的位置
pop元素出队,通过pop_heap函数使剩下的元素维持住堆的形式
top获取堆顶元素(优先级最大或最小的元素)
size返回队中有效数据个数
empty判断是否为空
swap交换两个优先级队列中的内容

示例代码:

#include<queue>
#include<iostream>using namespace std;void test1()
{priority_queue<int> pq;pq.push(1);pq.push(2);pq.push(3);pq.push(4);while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;priority_queue<int, vector<int>, greater<int>>pq2;pq2.push(1);pq2.push(2);pq2.push(3);pq2.push(4);while (!pq2.empty()){cout << pq2.top() << " ";pq2.pop();}cout << endl;
}int main()
{test1();return 0;
}

如何支持自定义类型使用priority_queue

1.使用仿函数

仿函数就是重载实现 ( ) ,使 ( ) 有实际的意义,因为使用的时候特别像函数调用,所以取名叫仿函数。例如我们有下面的一个类student,我们根据他的成绩_student从小到大进行排序:

#include<iostream>
#include<queue>
#include<vector>
using namespace std;class student
{
public:student(size_t id, size_t grade) :_id(id),_grade(grade){}size_t getId() const{return _id;}size_t getGrade() const{return _grade;}
private:size_t _id;size_t _grade;
};//先创建一个结构体cmp,struct访问权限是public
//里面构造仿函数,我们这里要实现从小到大排序,就要创建小堆,也就是greater的内容
struct cmp
{bool operator()(student& s1,student& s2) {return s1.getGrade() > s2.getGrade();}
};void test1()
{student s1(1,100);student s2(2,80);student s3(3,90);student s4(4,60);vector<student>s;s.push_back(s1);s.push_back(s2);s.push_back(s3);s.push_back(s4);priority_queue<student, vector<student>, cmp> pq;for (auto& e : s){pq.push(e);}while (!pq.empty()){student s = pq.top();cout << s.getId() << endl;pq.pop();}
}int main()
{test1();return 0;
}
2.通过运算符重载来实现自定义实现比较函数

当你使用 priority_queue 时,它需要一个比较函数或者比较对象来决定元素的排序。这个比较函数需要满足一定的要求,特别是它需要能够处理 const 对象。因为priority_queue底层本质上是一个堆,在我们进行插入删除的时候,需要不断调整,在我们调整的过程中是不希望元素的数值改变的。因此在底层我们的编译器只接受const修饰的元素。所以我们在进行operator>或operator<的时候,里面的参数是一定要加上const的。

#include<iostream>
#include<queue>
#include<vector>
using namespace std;class student
{
public:friend bool operator>(student& s1, student& s2);student(size_t id, size_t grade) :_id(id),_grade(grade){}size_t getId() const{return _id;}size_t getGrade() const{return _grade;}
private:size_t _id;size_t _grade;
};//struct cmp
//{
//	bool operator()(student& s1, student& s2) {
//		return s1.getGrade() > s2.getGrade();
//	}
//};bool operator>(const student& s1,const student& s2)//这里一定要加上const,只接收const对象
{return s1.getGrade() > s2.getGrade();
}void test1()
{student s1(1, 100);student s2(2, 80);student s3(3, 90);student s4(4, 60);vector<student>s;s.push_back(s1);s.push_back(s2);s.push_back(s3);s.push_back(s4);priority_queue<student, vector<student>, greater<student>> pq;for (auto& e : s){pq.push(e);}while (!pq.empty()){student s = pq.top();cout << s.getId() << endl;pq.pop();}
}int main()
{test1();return 0;
}

priority_queue的模拟实现

我们前面讲过优先级队列实际就是堆结构,我们要实现它就要先学习两个堆的算法:向上调整算法和向下调整算法。我们这里以构建大堆举例:

向上调整算法

void adjustUp(vector<int>& v,int child)
{int parent = (child - 1) / 2;while (child > 0){if (v[parent] < v[child]){swap(v[parent], v[child]);child = parent;parent = (parent - 1) / 2;}else{break;}}
}//这里我们要构建的是一个大堆,如果儿子的值大于父亲的值就交换位置继续迭代向上迭代

向下调整算法

//堆的向下调整(大堆)
void adjustDown(vector<int>& v, int parent)
{//child记录左右孩子中值较大的孩子的下标int child = 2 * parent + 1;//先默认其左孩子的值较大while (child < v.size()){if (child + 1 < v.size() && v[child] < v[child + 1])//右孩子存在并且右孩子比左孩子还大{child++;//较大的孩子改为右孩子}if (v[parent] < v[child])//左右孩子中较大孩子的值比父结点还大{//将父结点与较小的子结点交换swap(v[child], v[parent]);//继续向下进行调整parent = child;child = 2 * parent + 1;}else//已成堆{break;}}
}

模拟实现

模拟实现实际上就是在上面两个调整算法的基础上,设计几个接口:

namespace cyf
{template<class T>struct less{bool operator()(const T& t1, const T& t2){return t1 < t2;}};template<class T>struct greater{bool operator()(const T& t1, const T& t2){return t1 > t2;}};template<class T,class Container=vector<T>,class Compare=less<int>>class Mypriority_queue{public:void AdjustUp(int child){int parent = (child - 1) / 2;while (child != 0){if (com_(con_[parent], con_[child])){swap(con_[parent], con_[child]);child = parent;parent = (parent - 1) / 2;}else{break;}}}void AdjustDown(int parent){int child = 2 * parent + 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 = 2 * child + 1;}else{break;}}}void push(const T& val)//先尾插,再向上调整{con_.push_back(val);AdjustUp(con_.size() - 1);}int size(){return con_.size();}//先交换第一个元素和最后一个元素,之后将换后的最后一个元素删除,之后从0向下调整void pop(){swap(con_[0], con_[size() - 1]);con_.pop_back();AdjustDown(0);}T& top()//两种访问堆顶元素的top()函数{return con_[0];}const T& top() const{return con_[0];}bool empty() const{return con_.empty();}private:Container con_;//存储容器Compare com_;  //比较方式};
}

 以上就是有关优先级队列的全部内容,希望能对大家有所帮助!

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

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

相关文章

智慧博物馆的“眼睛”:视频智能监控技术守护文物安全与智能化管理

近日&#xff0c;位于四川德阳的三星堆博物馆迎来了参观热潮。据新闻报道&#xff0c;三星堆博物馆的日均参观量达1.5万人次。随着暑假旅游高峰期的到来&#xff0c;博物馆作为重要的文化场所&#xff0c;也迎来了大量游客。博物馆作为文化和历史的重要载体&#xff0c;其安全保…

关于vue实现导出excel表,以及导出的excel后的图片超过单元格的问题

实现导出带图标片的excel的方法&#xff0c; 首先&#xff1a; import table2excel from js-table2excel // 导出表格 按钮点击后触发事件 const onBatchExport () > {const column [//数据表单{title: "ID", //表头名称titlekey: "id", //数据ty…

通用图形处理器设计GPGPU基础与架构(四)

一、前言 本文将介绍GPGPU中线程束的调度方案、记分牌方案和线程块的分配与调度方案。 二、线程束调度 在计算机中有很多资源&#xff0c;既可以是虚拟的计算资源&#xff0c;如线程、进程或数据流&#xff0c;也可以是硬件资源&#xff0c;如处理器、网络连接或 ALU 单元。调…

Visual Studio2022中使用.Net 8 在 Windows 下使用 Worker Service 创建守护进程

Visual Studio2022中使用.Net 8 在 Windows 下创建 Worker Service 1 什么是 .NET Core Worker Service1.1 确认Visual Studio中安装了 ASP.NET和Web开发2 创建 WorkerService项目2.1 新建一个WorkerService项目2.2 项目结构说明3 将应用转换成 Windows 服务3.1 安装Microsoft.…

前端书籍翻页效果

目录 前端书籍翻页效果前言代码示例创建模板页面css样式编写js代码 结论 前端书籍翻页效果 前端实现翻书效果&#xff0c;附带vue源码 源码下载地址 前言 实际业务开发中&#xff0c;有时候会遇到需要在前端页面内实现翻书效果的需求&#xff0c;本篇文章就为大家介绍如何使…

09 深度推荐模型演化中的“平衡与不平衡“规律

你好&#xff0c;我是大壮。08 讲我们介绍了深度推荐算法中的范式方法&#xff0c;并简单讲解了组合范式推荐方法&#xff0c;其中还提到了多层感知器&#xff08;MLP&#xff09;。因此&#xff0c;这一讲我们就以 MLP 组件为基础&#xff0c;讲解深度学习范式的其他组合推荐方…

电子设备中丝杆模组高精度重复定位技术的原理!

丝杆模组是由螺旋丝杆和导杆组成的一种机械运动控制系统&#xff0c;通过在导杆内进行旋转&#xff0c;使导杆沿着线性方向进行移动&#xff0c;从而实现机械运动的线性控制。丝杆模组以其高精度、高稳定性和可重复定位的特性&#xff0c;在现代工业自动化和精密制造领域发挥着…

controller-from表单1

mvc模式是spring boot 开发web应用程序主要使用模式&#xff0c;mvc分别代表model模型&#xff0c;view是视图 &#xff0c;controller是控制器 controller是对接用户请求数据调用服务层代码&#xff0c;具体怎么操作 浏览器发送http请求给到dispatcherServlet&#xff08;前…

c++ primer plus 第16章string 类和标准模板库,string 类输入

c primer plus 第16章string 类和标准模板库,string 类输入 c primer plus 第16章string 类和标准模板库,string 类输入 文章目录 c primer plus 第16章string 类和标准模板库,string 类输入16.1.2 string 类输入程序清单 16.2 strfile.cpp 16.1.2 string 类输入 对于类&…

【操作系统】文件管理——文件存储空间管理(个人笔记)

学习日期&#xff1a;2024.7.17 内容摘要&#xff1a;文件存储空间管理、文件的基本操作 在上一章中&#xff0c;我们学习了文件物理结构的管理&#xff0c;重点学习了操作系统是如何实现逻辑结构到物理结构的映射&#xff0c;这显然是针对已经存储了文件的磁盘块的&#xff0…

题解|2023暑期杭电多校03

【原文链接】 &#xff08;补发&#xff09;题解|2023暑期杭电多校03 1011.8-bit Zoom 不那么签到的签到题、模拟题 题目大意 给定一个 n n n\times n nn 大小的字符矩阵表示一张图片&#xff0c;每种字符代表一种颜色&#xff1b;并给定 Z Z Z 代表缩放倍率 满足以下条…

无人驾驶的未来:AI如何重塑我们的出行世界

无人驾驶汽车&#xff0c;作为人工智能&#xff08;AI&#xff09;技术的集大成者&#xff0c;正以前所未有的速度改变着我们的出行方式。从机器学习到计算机视觉&#xff0c;再到人工智能生成内容&#xff08;AIGC&#xff09;&#xff0c;AI技术的每一次进步都在为无人驾驶汽…

Linux内核编程(八) 添加自定义目录驱动菜单 (Kconfig文件使用)

本文目录 一、Linux 内核驱动目录二、自定义驱动的Kconfig编写●示例&#xff1a;在 drivers 菜单添加一个自己驱动的子菜单。 三、自写驱动的Makefile编写四、总结 一个Linux内核源码&#xff0c;其中包含了很多驱动程序&#xff0c;对应不同的功能。我们在编译内核时。如果将…

设计模式:真正的建造者模式

又臭又长的set方法 经常进行Java项目开发使用各类starter的你一定见过这种代码&#xff1a; public class SwaggerConfig {Beanpublic Docket api() {return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.any()).paths(PathSelectors.any…

【BUG】已解决:ModuleNotFoundError: No module named ‘cv2’

已解决&#xff1a;ModuleNotFoundError: No module named ‘cv2’ 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;武汉城市开…

【Pyhton】Pip换源(Windows)

在Python中使用pip换源的方法可以通过修改pip配置文件来实现。具体步骤如下&#xff1a; 暂时修改&#xff08;只应用于本次下载&#xff09; pip install 库名 -i 国内源链接/simple --trusted-host 国内源链接 常见的国内源链接见下方永久修改中的内容。 示例&#xff1a…

【ffmpeg命令入门】ffmpeg转码过程

文章目录 前言转码图示过程含义总结 前言 在数字媒体处理领域&#xff0c;ffmpeg 是一款非常强大的工具&#xff0c;它支持多种音视频格式&#xff0c;可以进行转码、剪辑、滤镜等操作。ffmpeg 的强大功能和灵活性使其成为了音视频处理的首选工具。然而&#xff0c;由于其功能…

python-Web

FLASK整体框架: from flask import Flask,render_templateapp Flask(__name__)app.route("/show/info")#网址 def index():#网址对应的函数return render_template("index.html")#falsk 支持将字符串写入文件if __name____main__:app.run()#访问网站的时…

Java中的压缩与解压缩操作详解

Java中的压缩与解压缩操作详解 在Java编程中&#xff0c;处理压缩和解压缩文件是一个常见的需求。Java提供了多种方式来实现这些操作&#xff0c;包括使用标准的Java类库和第三方库。 本文将介绍如何使用Java进行压缩和解压缩操作&#xff0c;涵盖基本的压缩文件格式如ZIP以及…

获取JVM虚拟机的内存和CPU核心数

获取内存和核心数量 Runtime runtime Runtime.getRuntime();long freeMemory runtime.freeMemory();long maxMemory runtime.maxMemory();long totalMemory runtime.totalMemory();int availableProcessors runtime.availableProcessors();System.out.println("空闲内…