c++学习之优先级队列

目录

1.初识优先级队列   

库中的实现

使用优先级队列

2.优先级队列的实现

3.仿函数

利用仿函数实现的优先级队列

迭代器区间构造(建堆)


1.初识优先级队列   

    如果我们给每个元素都分配一个数字来标记其优先级,不妨设较小的数字具有较高的优先级,这样我们就可以在一个集合中访问优先级最高的元素并对其进行查找和删除操作了。这样,我们就引入了优先级队列 这种数据结构。 优先级队列(priority queue) 是0个或多个元素的集合,每个元素都有一个优先权,对优先级队列执行的操作有     

优先队列也是一种抽象数据类型。优先队列中的每个元素都有优先级,而优先级高(或者低)的将会先出队,而优先级相同的则按照其在优先队列中的顺序依次出队。

库中的实现

对于库中的实现,参数来说,可以看到也是给了容器模版(适配器),还给了缺省参数为vector。

其次有一个compare参数(默认下给了缺省参数less的一个对象),实际上还有一个对象greater,这决定了优先级是较大的优先(less),还是较小的优先(greater)。

注意这里与库中的sort的排序顺序是相反的。

       对于接口我们可以看到它与栈的结构很像,其次与堆的结构的结构也很像(我们在数据结构部分知道取堆顶元素),再结合优先级队列的概念,寻找元素的大小,仔细想想:那么实际上优先级队列是一个堆的结构,利用建大堆的方式获取最大的元素等。

实际上对于适配器,我们不仅仅只是数组,我们也可以传双端队列作为适配器也是可以的。

使用优先级队列

简单的使用下,我们可以看到这里在默认的情况下较大的数一个个输出,故默认情况下这里给的是大堆,取堆顶元素便是最大的(删除元素-我们调换堆顶的元素与末尾的元素,向下调整)。

因为是堆的结构,故我们可以知道优先级队列插入删除的时间线复杂度为logN,

void test() 
{priority_queue<int,vector<int> > p;//取大的  大堆//priority_queue<int,vector<int> ,greater<int> > p;//取小的  小堆//入队 p.push(1);p.push(2);p.push(3);p.push(4);p.push(5);p.push(6);//打印并出队 while(!p.empty()){cout<<p.top();p.pop();} } 

通过给出参数的不同,我们可以改变优先级是大或是小。

2.优先级队列的实现

明白了优先级队列的结构之后,我们自己也可以简单实现一下优先级队列。

 这里我们先不知道compare是个啥,我们先实现出默认的大堆结构,也就是大的优先,然后就是给出类型模版和适配器。

//默认实现大的优先级队列 
namespace mypriority_queue
{template<class T,class Container = vector<T> >class priority_queue{public://入优先级队列,本质上就是建大堆 void push(cosnt T& x){//尾插_con.push_back(x); //向上调整 adjust_up(_con.size()-1);//从尾插的位置想上调整 (尾插前size(),故减一) }void adjust_up(int child){size_t parent=(child-1)/2;while(child>0){if(_con[child]>_con[parent]&&child>parent){swap(_con[child],_con[parent]);	child=parent;paren=(parent-1)/2;}					}else{break;}		}//出优先级队列,删除堆顶元素(先交换,在尾删,在向下调整)void pop(){swap(_con[_con.size()-1],_con[0]);_con.pop_back();adjust_down(0);}	void adjust_down(int parent){size_t child=parent*2+1;while(parent<_con.size()){if(child+1<_con.size()&&_con[chid+1]>a[parent]){++child;												}if(_con[chid]>a[parent]){swap(_con[child],_con[parent]);parent=child;child=child*2+1;}}else{break;}}const T& top(){return _con[0];}bool empty(){return _con.empty();}size_t size(){return _con.size();}private:Container _con;}} 

其中拷贝构造等都不需要我们实现了,系统在调用时会调用我们的容器里的。

3.仿函数

上面已经实现了优先级队列以较大的为优先,那么较小的,我们也可以在实现一个,改变一下向上调整与向上调整的比较符号为小于,就是以小的为优先也就是小堆。

可是我们在用的时候没必要为两份差不多相同的代码搞两个的容器来让我们调用,需要大的用大的,要小的用小的,那么有没有办法可以通过参数的不同的就能直接改变函数成为大堆或小堆,即通过参数不同改变函数。

c++提供了仿函数来实现:

仿函数(functor),就是使一个类的使用看上去像一个函数。其实本质就是类中实现一个重载(),operator(),这个类就有了类似函数的行为,就是一个仿函数类了。

如下:

class Less
{
public:bool operator()(int x,int y){return x>y;}
};
int main()
{Less less;cout<<less(2,3);cout<<less.operator()(2,3);//两者本质一样 return 0;
}

实际上本质上是一个类,类中实现了重载(),简写的时候,本质上是对象调用方法,但看起来像函数调用。

通过仿函数我们就可以实现利用对象调用函数,重载的越多,对象可以调用的也就多了,以这种方式优先级队列可以通过传对象的方法来实现,大的优先级和小的优先级都可以调用

利用仿函数实现的优先级队列

一般使用的时候我们都是将模版与重载()结合起来。

改变传参的仿函数就是改变比较的符号,在通过对象调用:

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;}
};
namespace mypriority_queue
{template<class T,class Container = vector<T> ,class compare=Less<T> >class priority_queue{compare com;public://入优先级队列,本质上就是建大堆 void push(const T& x){//尾插_con.push_back(x); //向上调整 adjust_up(_con.size()-1);//从尾插的位置想上调整 (尾插前size(),故减一) }void adjust_up(int child){int parent=(child-1)/2;while(child>0){if(com(_con[child],_con[parent])&&child>parent){swap(_con[child],_con[parent]);	child=parent;parent=(parent-1)/2;}					}else{break;}		}//出优先级队列,删除堆顶元素(先交换,在尾删,在向下调整)void pop(){swap(_con[_con.size()-1],_con[0]);_con.pop_back();adjust_down(0);}	void adjust_down(int parent){size_t child=parent*2+1;while(parent<_con.size()){if(_con.size>child+1&&com(_con[child+1],a[parent])){++child;												}if(com(_con[child],a[parent])){swap(_con[child],_con[parent]);parent=child;child=child*2+1;}}else{break;}}const T& top(){return _con[0];}bool empty(){return _con.empty();}size_t size(){return _con.size();}private:Container _con;}} 

对于c++提供的仿函数我们也可以用此替换函数指针,函数指针在实际的应用上比较麻烦,我们可以利用仿函数替换他。

那么现在我们就知道在库中就已经有实现的less和greater,我们可以直接调用库中的。

当然除了库中提供的的less与greater外,我们还可以实现自己所需要的类型的比较,比如对Data类型的数据作比较,我们可以实现自己的仿函数,在通过参数传递用来实现Data类比较。

其次算法库中也提供了许多对于堆的一些判断接口等:

可以看到有堆排序,建堆,出入堆等接口。

迭代器区间构造(建堆)

在原有基础上,添加了另一种初始化的方法,利用迭代器区间来直接完成建堆:

priority_queue(){} //迭代器区间初始化template <class Inputiterator>priority_queue(Inputoriterator first,Inputoriterator last):_con(first,last)//容器提供有迭代器区间初始化 {//建堆:初始化之后--向下调整 for(int i=(_con.size()-2)/2;i>=0;i--){//堆从最后一个parent开始调整 adjust_down(i);}}

因为容器本身具有迭代器区间初始化,我们只需要再次调整即可,此外因为我们自己写入了带有参数的构造函数,那么就需要再补充一个本身的无参构造即可。

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

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

相关文章

怎么通过portainer部署一个vue项目

这篇文章分享一下今天通过docker打包vue项目&#xff0c;并使用打包的镜像在portainer上部署运行&#xff0c;参考了vue-cli和docker的官方文档。 首先&#xff0c;阅读vue-cli关于docker部署的说明 vue-cli关于docker部署的说明https://cli.vuejs.org/guide/deployment.html#…

网络层常见协议——IPV4、IPV6、ARP、ICMP、QoS

目录 1、IPV4 协议 IPV4 地址的组成&#xff1a; IPV4地址的分类&#xff1a; 关于多播和组播&#xff1a; 常见组播地址分类&#xff1a; 特殊的 IPV4 地址&#xff1a; 私有地址和公有地址&#xff1a; 私有地址的范围&#xff1a; 子网划分&#xff1a; 子网掩码&…

操作系统--分页存储管理

一、概念介绍 分页存储&#xff1a;一是分内存地址&#xff0c;二是分逻辑地址。 1.分内存地址 将内存空间分为一个个大小相等的分区。比如&#xff0c;每个分区4KB。 每个分区就是一个“页框”&#xff0c;每个页框有个编号&#xff0c;即“页框号”&#xff0c;“页框号”…

【统计学】Top-down自上而下的角度模型召回率recall,精确率precision,特异性specificity,模型评价

最近在学 logistic regression model&#xff0c;又遇见了几个之前的老面孔。 召回率recall, 精确率precision&#xff0c;特异性spcificity&#xff0c;准确率accuracy&#xff0c;True positive rate&#xff0c;false positive rate等等名词在学习之初遇到的困难在于&#x…

【Java每日一题】— —第十八题:求二维数组中的元素最小值及其索引。(2023.10.02)

&#x1f578;️Hollow&#xff0c;各位小伙伴&#xff0c;今天我们要做的是第十八题。 &#x1f3af;问题&#xff1a; 求二维数组中的元素最小值及其索引。 测试结果如下&#xff1a; &#x1f3af; 答案&#xff1a; int [][]anew int[3][];a[0]new int [3];a[1]new int[5…

UG NX二次开发(C#)- 制图(Draft)-工程图框选制图曲线并输出制图曲线的信息

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1、前言2、在UG NX中打开一个装配体模型3、进入工程制图模块,创建工程制图4、在VS中创建一个工程项目5、在Main()中添加选择的代码(UFun)6、在Main()中添加选择的代码(NXOpen)7、框选解决方案…

全国排名前三的直播公司无锋科技入驻天府蜂巢成都直播产业基地

最近&#xff0c;全国排名前三的直播公司——无锋科技&#xff0c;正式宣布入驻位于成都的天府蜂巢直播产业基地&#xff0c;这一消息引起了业内人士的高度关注。成都直播产业基地一直是中国直播产业的重要地标之一&#xff0c;其强大的技术和资源优势为众多直播公司提供了广阔…

自动驾驶:路径规划概述

自动驾驶&#xff1a;路径规划概述 全局路径规划Dijkstra算法A*算法RRT&#xff08;随机快速探索树&#xff09;算法PRM&#xff08;概率路线图&#xff09;算法 局部路径规划DWA&#xff08;动态窗口法&#xff09;算法TEB&#xff08;时间弹性带&#xff09;算法Lattice Plan…

postgresql-管理表空间

postgresql-管理表空间 基本概念创建表空间用户授权移动表空间 修改表空间移动表空间位置 删除表空间 基本概念 在 PostgreSQL 中&#xff0c;表空间&#xff08;tablespace&#xff09;表示数据文件的存放目录&#xff0c;这些数据文件代表了数 据库的对象&#xff0c;例如表…

Oracle SQL Developer 中查看表的数据和字段属性、录入数据

在Oracle SQL Developer中&#xff0c;选中一个表时&#xff0c;右侧会列出表的情况&#xff1b;第一个tab是字段的名称、数据类型等属性&#xff1b; 切换到第二个tab&#xff0c;显示表的数据&#xff1b; 这和sql server management studio不一样的&#xff1b; 看一下部门…

代谢组学分析手段(一)

核磁共振技术&#xff08;Nuclear Magnetic Resonance, NMR&#xff09; 定义&#xff1a;指核磁矩不为零的原子核在外磁场的作用下&#xff0c;核自旋能级发生塞曼分裂&#xff0c;共振吸收某一特定频率的射频辐射的物理过程。 优点&#xff1a; &#xff08;1&#xff09;…

基于Matlab实现logistic方法(源码+数据)

Logistic回归是一种常用的分类算法&#xff0c;适用于二分类问题。本文将介绍如何使用Matlab实现Logistic回归方法&#xff0c;并通过一个示例演示其应用。 文章目录 引言实现步骤1. 数据准备2. 特征缩放3. 模型训练4. 模型评估 源码数据下载 引言 Logistic回归是一种广泛应用…

NodeJS 如何连接 MongoDB

初始化&#xff1a; yarn init使用命令&#xff1a; yarn add mongodb新建 index.js 文件&#xff1a; const MongoClient require(mongodb).MongoClient; const db_name "fly_articleDb"; const url mongodb://127.0.0.1:27017;(async function () {const cli…

常用的分布式ID解决方案原理解析

目录 前言 一&#xff1a;分布式ID的使用场景 二&#xff1a;分布式ID设计的技术指标 三&#xff1a;常见的分布式ID生成策略 3.1 UUID 3.2 数据库生成 3.3 数据库的多主模式 3.4 号段模式 3.5 雪花算法 前言 分布式ID的生成是分布式系统中非常核心的基础性模块&#…

【C语言】宏定义

&#x1f6a9; WRITE IN FRONT&#x1f6a9; &#x1f50e; 介绍&#xff1a;"謓泽"正在路上朝着"攻城狮"方向"前进四"&#x1f50e;&#x1f3c5; 荣誉&#xff1a;2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评百大博…

Docker下如何构建包含延迟插件的RabbitMQ镜像

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…

js题解(三)

文章目录 柯里化模块乘法改变上下文 柯里化 已知 fn 为一个预定义函数&#xff0c;实现函数 curryIt&#xff0c;调用之后满足如下条件&#xff1a; 1、返回一个函数 a&#xff0c;a 的 length 属性值为 1&#xff08;即显式声明 a 接收一个参数&#xff09; 2、调用 a 之后&a…

【改造中序遍历算法】1038. 从二叉搜索树到更大和树

1038. 从二叉搜索树到更大和树 解题思路 改造中序遍历算法先遍历右子树 然后累加当前节点的值 再遍历左子树 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode…

OpenGLES:绘制一个彩色、旋转的3D圆柱

一.概述 上一篇博文讲解了怎么绘制一个彩色旋转的立方体 这一篇讲解怎么绘制一个彩色旋转的圆柱 圆柱的顶点创建主要基于2D圆进行扩展&#xff0c;与立方体没有相似之处 圆柱绘制的关键点就是将圆柱拆解成&#xff1a;两个Z坐标不为0的圆 一个长方形的圆柱面 绘制2D圆的…

MATLAB算法实战应用案例精讲-【优化算法】混合领导优化算法(HLBO)(附MATLAB和Python代码实现)

代码实现 MATLAB HLBO.m function[Best_score,Best_pos,HLBO_curve]=HLBO(SearchAgents,Max_iterations,lowerbound,upperbound,dimension,fitness)lowerbound=ones(1,dimension).*(lowerbound); % Lower limit for variables upperbound=ones(…