c++学习之优先级队列

news2024/11/23 2:24:39

目录

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.coloradmin.cn/o/1057566.html

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

相关文章

2023年中国新能源汽车电动助力转向系统行业现状分析:随着新能源汽车的发展,产品渗透率的提升[图]

电动助力转向(EPS)系统是传统转向系统&#xff08;如液压和电动液压系统&#xff09;的替代品。自动驾驶汽车的日益普及正在推动全球电动助力转向系统市场的需求增长。配备电动助力转向系统的车辆总重量趋于减轻&#xff0c;从而进一步提高燃油效率&#xff0c;其中2022年中国新…

Nginx之Openresty基本使用解读

目录 Openresty基本介绍 Openresty源码编译安装 Openresty基本使用 测试lua脚本 外部分文件导入 关闭缓存&#xff0c;开启热部署 用lua代码获取系统变量 Openresty基本介绍 OpenResty是一个基于 Nginx 与 Lua 的高性能 Web 平台&#xff0c;其内部集成了大量精良的 Lua…

2023年中国纯棉纱行业现状及发展前景分析[图]

棉纱是棉纤维经纺纱工艺加工而成的纱&#xff0c;经合股加工后称为棉线。根据纺纱的不同工艺&#xff0c;可分为普梳纱和精梳纱。精梳纱选用优质原料&#xff0c;成纱中纤维伸直平行、结杂少、光泽好、条干匀、强力高&#xff0c;这类棉纱多用于织造高档。 棉纱分类 资料来源&…

2023年中国汽车座舱行业发展现状及趋势分析:高级人机交互(HMI)系统将逐步提升[图]

2022年有22.3%的汽车用户认为座舱内车载娱乐功能成为影响使用体验的关键因素。当前智能电动汽车的用户画像与娱乐、游戏等应用的用户画像相似&#xff0c;均以年轻人作为目标用户。年轻化的用户将娱乐功能的使用习惯延伸至汽车座舱内&#xff0c;对于座舱功能的需求不再局限于导…

【C语言】宏定义

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

RFID藏品管理系统-智慧文物仓库管理系统

一、项目背景 RFID藏品管理系统DW-S407是一套成熟系统&#xff0c;依托互3D技术、云计算、大数据、RFID技术、智能传感器、AI、视频分析技术对文物仓库进行统一管理、分析的信息化、智能化、规范化的系统。 不管是博物馆还是艺术馆&#xff0c;藏品的管理都是非常复杂的。特…

使用Docker部署ElasticSearch7+ELK(附带ES操作操作命令集)

ElasticSearch 7ELK 程序安装Docker安装下载ES镜像提前创建挂载文件夹添加配置文件创建并启动容器可能出现的异常安装IK分词使用ElasticHD客户端工具(目前使用发现无法做增删改)安装Kibana 软件包安装安装ElasticSearch&#xff08;需要JDK1.8&#xff09;安装IK&#xff08;下…

【高阶数据结构】哈希(哈希表、哈希桶)

⭐博客主页&#xff1a;️CS semi主页 ⭐欢迎关注&#xff1a;点赞收藏留言 ⭐系列专栏&#xff1a;C进阶 ⭐代码仓库&#xff1a;C进阶 家人们更新不易&#xff0c;你们的点赞和关注对我而言十分重要&#xff0c;友友们麻烦多多点赞&#xff0b;关注&#xff0c;你们的支持是我…

Codeforces Round 901 (Div. 2)

Problem - A - Codeforces 贪心 每次都先让b减到1&#xff0c;然后再去选择工具来增加时间 AC代码: #include<bits/stdc.h> #define endl \n #define int long long using namespace std; const int N110; int x[N]; int a,b,n; void solve() {cin>>a>>b…

【C语言】模拟实现strlen

strlen是非常常用的字符串函数 目录 介绍&#xff1a;模拟实现&#xff1a;计数器递归指针-指针 介绍&#xff1a; 我们可得这个函数是求在字符串开始与\0之间的字符串长度 代码示例&#xff1a; #include <stdio.h> int main() {const char* str1 "abcdef"…

神器 CodeWhisperer

这两天看到了好多关于 Amazon CodeWhisperer 针对个人用户终身免费使用的消息&#xff0c;便抽空简单来重点介绍下如何在 VS Code 这款 IDE 上安装和使用 CodeWhisperer。 亚马逊云科技开发者社区为开发者们提供全球的开发技术资源。这里有技术文档、开发案例、技术专栏、培训视…

Linux——进程间通信——system V系列

✅<1>主页&#xff1a;&#xff1a;我的代码爱吃辣 &#x1f4c3;<2>知识讲解&#xff1a;Linux——进程间通信——system V系列 ☂️<3>开发环境&#xff1a;Centos7 &#x1f4ac;<4>前言&#xff1a;system V 版本进程间通信的机制。 目录 一.共享…

WebGPU 入门:绘制一个三角形

大家好&#xff0c;我是前端西瓜哥。 今天我们来入门 WebGPU&#xff0c;来写一个图形版本的 Hello World&#xff0c;即绘制一个三角形。 WebGPU 是什么&#xff1f; WebGPU 是一个正在开发中的潜在 Web 标准和 JavaScript API&#xff0c;目标是提供 “现代化的 3D 图形和计…

AutoCAD 产品设计:图形单位

本文讲解 AutoCAD 产品的图形单位功能产品设计&#xff0c;没有任何代码实现。 使用的 AutoCAD 为 2020 版本 图形单位是什么&#xff1f; 图形单位是用于设置 一些属性数据应该用什么格式显示 的命令&#xff0c;命令标识为 un&#xff08;units&#xff09;。 举个例子。 …

操作EXCEL计算3万条数据的NDVI并填入

Python操作EXCEL&#xff0c;计算3万条数据的NDVI并填入 问题描述 现在是有构建好了的查找表&#xff0c;不过构建了3万条数据&#xff0c;在excel中手动计算每行的NDVI值太麻烦了&#xff0c;也不会操作。 就试试python吧&#xff0c;毕竟python自动处理大型EXCEL数据很方便…

黑马头条项目环境搭建

注册中心网关配置 spring:cloud:gateway:globalcors:add-to-simple-url-handler-mapping: truecorsConfigurations:[/**]:allowedHeaders: "*"allowedOrigins: "*"allowedMethods:- GET- POST- DELETE- PUT- OPTIONroutes:# 平台管理- id: useruri: lb://…

51单片机可调幅度频率波形信号发生器( proteus仿真+程序+原理图+报告+讲解视频)

51单片机可调幅度频率信号发生器( proteus仿真程序原理图报告讲解视频&#xff09; 讲解视频1.主要功能&#xff1a;2.仿真3. 程序代码4. 原理图4. 设计报告5. 设计资料内容清单&&下载链接***[资料下载链接](https://docs.qq.com/doc/DS1daV1BKRXZMeE9u)*** 51单片机可…

数据结构——计数与归并非递归

排序算法 前言一、归并的非递归实现二、计数排序三、序算法复杂度及稳定性分析总结 前言 重要的事说三遍&#xff01; 学习&#xff01;学习&#xff01;学习&#xff01; 努力!努力!努力&#xff01; 一、归并的非递归实现 代码实现&#xff1a; void MergeSortNonR(int* a,…

3分钟在移动盘上安装Ubuntu系统和ROS2

目录 原视频准备烧录 一个usb移动固态硬盘可以干什么呢&#xff1f; 可以用移动盘解决电脑存储空间不足的问题&#xff0c;可以用移动盘存储数据&#xff0c;可以用移动盘装其他系统当做双系统来使用&#xff0c;可以在一个移动固态硬盘里装两个甚至更多的系统… 下面&#xf…

《C++ primer plus》精炼(OOP部分)——对象和类(8)

学习是一项持续的投资&#xff0c;永远不会白费——本杰明富兰克林 文章目录 第13章&#xff1a;类继承一个基类和派生类公有继承的逻辑关系&#xff1a;is-a多态公有继承 第13章&#xff1a;类继承 一个基类和派生类 从一个类派生出另一个类时&#xff0c;原始类称为基类&am…