【C++】STL-priority_queue

目录

1、priority_queue的使用

2、实现没有仿函数的优先级队列

3、实现有仿函数的优先级队列

3.1 仿函数

3.2 真正的优先级队列

3.3 优先级队列放自定义类型

1、priority_queue的使用

priority_queue是优先级队列,是一个容器适配器,不满足先进先出的特点,而是优先级高的先出,默认的适配器是vector,底层是一个堆,默认是大堆

priority_queue是可以进行迭代器区间初始化的

void test_priority_queue1()
{
	vector<int> v = { 3,2,7,6,0,4,1,9,8,5 };
	priority_queue<int> q1;
	for (auto& e : v)
		q1.push(e);
	while (!q1.empty())
	{
		cout << q1.top() << " ";
		q1.pop();
	}
	cout << endl;
}
void test_priority_queue2()
{
	vector<int> v = { 3,2,7,6,0,4,1,9,8,5 };
	priority_queue<int> q1(v.begin(), v.end());
	while (!q1.empty())
	{
		cout << q1.top() << " ";
		q1.pop();
	}
	cout << endl;
}

可以用数组直接初始化 

void test_priority_queue3()
{
	int v[10] = {3,2,7,6,0,4,1,9,8,5};
	priority_queue<int> q1(v, v + 10);
	while (!q1.empty())
	{
		cout << q1.top() << " ";
		q1.pop();
	}
	cout << endl;
}

上面3段代码的结果都是相同的,都是9 8 7 6 5 4 3 2 1 0,因为默认是建大堆

2、实现没有仿函数的优先级队列

namespace cxf
{
	template<class T,class Container = std::vector<T>>
	class priority_queue
	{
	public:// 建大堆
		void adjust_up(int child)
		{
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				if (_con[parent] < _con[child])
				{
					std::swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else break;
			}
		}
		void adjust_down(int parent)
		{
			int child = parent * 2 + 1;
			while (child < _con.size())
			{
				if (child + 1 < _con.size() && _con[child] < _con[child + 1])
				{
					++child;
				}
				if (_con[parent] < _con[child])
				{
					std::swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else break;
			}
		}
		// 强制编译器生成默认的构造函数,因为下面有迭代器区间初始化,这样没办法用默认构造函数
		priority_queue() = default;
		// 迭代器区间初始化
		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				_con.push_back(*first);
				++first;
			}
			// 建堆
			for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
			{
				adjust_down(i);
			}
		}
		void push(const T& x)
		{
			_con.push_back(x);
			adjust_up(_con.size() - 1);
		}
		void pop()
		{
			std::swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjust_down(0);
		}
		const T& top()
		{
			return _con[0];
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
}

上面是建大堆的优先级队列,当要建小堆时,需要在adjust_up和adjust_up中将<改成>,这样是十分麻烦的,为例能够在不修改代码的情况下完成建小堆,所以引入了仿函数的概念

3、实现有仿函数的优先级队列

3.1 仿函数

仿函数就是重载了operatror()的类,类的对象可以像调用函数一样使用

operator()的特点是参数个数和返回值个数可以根据需求来定,很灵活,所以有很多用法

若用class来定义仿函数的类要加public,所以通常会用struct来定义仿函数

根据仿函数就可以来实现一个既可建大堆,又可建小堆的优先级队列

3.2 真正的优先级队列

namespace cxf
{
	template<class T>
	class myless // 小于是大堆
	{
	public:
		bool operator()(const T& x, const T& y)
		{
			return x < y;
		}
	};
	template<class T>
	class mygreater // 大于是小堆
	{
	public:
		bool operator()(const T& x, const T& y)
		{
			return x > y;
		}
	};
	template<class T, class Container = std::vector<T>, class Comapre = myless<T>>
	class priority_queue
	{
	public:
		void adjust_up(int child)
		{
			Comapre comfunc;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				//if (_con[parent] < _con[child])
				if(comfunc(_con[parent],_con[child]))
				{
					std::swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else break;
			}
		}
		void adjust_down(int parent)
		{
			Comapre comfunc;
			int child = parent * 2 + 1;
			while (child < _con.size())
			{
				/*if (child + 1 < _con.size() && _con[child] < _con[child + 1])*/
				if (child + 1 < _con.size() && comfunc(_con[child], _con[child + 1]))
				{
					++child;
				}
				//if (_con[parent] < _con[child])
				if(comfunc(_con[parent],_con[child]))
				{
					std::swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else break;
			}
		}
		// 强制编译器生成默认的构造函数,因为下面有迭代器区间初始化,这样没办法用默认构造函数
		priority_queue() = default;
		// 迭代器区间初始化
		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				_con.push_back(*first);
				++first;
			}
			// 建堆
			for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
			{
				adjust_down(i);
			}
		}
		void push(const T& x)
		{
			_con.push_back(x);
			adjust_up(_con.size() - 1);
		}
		void pop()
		{
			std::swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjust_down(0);
		}
		const T& top()
		{
			return _con[0];
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;
	};
}

priority_queue的第三个模板参数就是仿函数 

在STL库中的priority_queue来建小堆

3.3 优先级队列放自定义类型

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}

	bool operator<(const Date& d)const
	{
		return (_year < d._year) ||
			(_year == d._year && _month < d._month) ||
			(_year == d._year && _month == d._month && _day < d._day);
	}

	bool operator>(const Date& d)const
	{
		return (_year > d._year) ||
			(_year == d._year && _month > d._month) ||
			(_year == d._year && _month == d._month && _day > d._day);
	}

	friend ostream& operator<<(ostream& _cout, const Date& d);
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
	_cout << d._year << "-" << d._month << "-" << d._day;
	return _cout;
}
int main()
{
	priority_queue<Date> q1;
	q1.push(Date(2022, 9, 9));
	q1.push(Date(2022, 9, 10));
	q1.push(Date(2022, 9, 11));
	while (!q1.empty())
	{
		cout << q1.top() << endl;
		q1.pop();
	}
	return 0;
}

结果是正确的,因为只要这个自定义类型是能够比较大小的,都能使用优先级队列

但是若比较的不是这个自定义类型,而是这个自定义类型的指针,则会出现随机结果

int main()
{
	priority_queue<Date*> q1;
	q1.push(new Date(2022, 9, 9));
	q1.push(new Date(2022, 9, 10));
	q1.push(new Date(2022, 9, 11));
	while (!q1.empty())
	{
		cout << *q1.top() << endl;
		q1.pop();
	}
	return 0;
}

此时是错误的,并且每次运行程序结果也不一定都相同。因为less比较的是Date*,是根据地址比较的,而new出来的地址是随机的,所以几次的运行结果也会不同。而且这个比较从逻辑上就是错误的,因为不应该使用对象的地址去比较,应该使用对象的值去比较

所以可以自己写一个仿函数,达到想要的目的

struct PDateLess
{
	bool operator()(Date* p1, Date* p2)
	{
		return *p1 < *p2;
	}
};
int main()
{
	priority_queue<Date*, vector<Date*>, PDateLess> q1;
	q1.push(new Date(2022, 9, 9));
	q1.push(new Date(2022, 9, 10));
	q1.push(new Date(2022, 9, 11));
	while (!q1.empty())
	{
		cout << *q1.top() << endl;
		q1.pop();
	}
	return 0;
}

此时就正确的

所以仿函数不仅可以支持比较大小,还可以支持修改比较逻辑,如果默认的比较逻辑不是想要的或者不支持比较大小,都可以通过仿函数来控制。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pdf拆分,pdf拆分在线使用,pdf拆分多个pdf

在数字化的时代&#xff0c;pdf文件已经成为我们日常办公、学习不可或缺的文档格式。然而&#xff0c;有时候我们可能需要对一个大的pdf文件进行拆分&#xff0c;以方便管理和分享。那么&#xff0c;如何将一个pdf文件拆分成多个pdf呢&#xff1f;本文将为你推荐一种好用的拆分…

监控平台zabbix介绍与部署

目录 1.为什么要做监控 2.zabbix是什么&#xff1f; 3.zabbix 监控原理 4.Zabbix 6.0 新特性 5.Zabbix 6.0 功能组件 6.部署zabbix 6.1 部署 Nginx PHP 环境并测试 6.2 部署数据库 6.3 向数据库导入 zabbix 数据 6.4 编译安装 zabbix Server 服务端 6.5 修改 zabbix…

中小企业如何防止被查盗

在当前的商业环境中&#xff0c;小企业面临诸多挑战&#xff0c;其中之一便是如何在有限的预算内满足日常运营的技术需求。由于正版软件的高昂成本&#xff0c;一些小企业可能会选择使用盗版软件来降低成本。 我们联网之后存在很多风险&#xff0c;你可以打开自己的可以联网的电…

【面试系列】机器学习工程师高频面试题及详细解答

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来&#xff1a;详细讲解AIGC的概念、核心技术、…

Java--创建对象内存分析

1.如图所示&#xff0c;左边为一个主程序&#xff0c;拥有main方法&#xff0c;右边定义了一个Pet类&#xff0c;通过debug不难看出&#xff0c;当启动该方法时&#xff0c;有以下该步骤 1.运行左边的实例化Pet类对象 2.跳转至右边定义Pet类的语句 3.跳回至左边获取Pet类基本属…

代码生成器使用指南,JeecgBoot低代码平台

JeecgBoot 提供强大的代码生成器&#xff0c;让前后端代码一键生成&#xff0c;实现低代码开发。支持单表、树列表、一对多、一对一等数据模型&#xff0c;增删改查功能一键生成&#xff0c;菜单配置直接使用。 同时提供强大模板机制&#xff0c;支持自定义模板&#xff0c;目…

【bug报错已解决】ERROR: Could not find a version that satisfies the requirement

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 引言一、问题描述1.1 报错示例1.2 报错分析 二、解决方法2.1 方法一2.2 方法二 三、总结 引言 有没有遇到过那种让人…

JSON JOLT常用示例整理

JSON JOLT常用示例整理 1、什么是jolt Jolt是用Java编写的JSON到JSON转换库&#xff0c;其中指示如何转换的"specification"本身就是一个JSON文档。以下文档中&#xff0c;我统一以 Spec 代替如何转换的"specification"json文档。以LHS(left hand side)代…

kaggle量化赛金牌方案(第七名解决方案)

获奖文章(第七名解决方案) 致谢 我要感谢 Optiver 和 Kaggle 组织了这次比赛。这个挑战提出了一个在金融市场时间序列预测领域中具有重大和复杂性的问题。 方法论 我的方法结合了 LightGBM 和神经网络模型,对神经网络进行了最少的特征工程。目标是结合这些模型以降低最终…

arco disign vue 日期组件的样式穿透

问题描述: 对日期组件进行样式穿透. 原因分析: 如图,日期组件被展开时它默认将dom元素挂载到body下, 我们的页面在idroot的div 里层, 里层想要穿透外层是万万行不通的. 解决问题: 其实官网提供了参数,但是并没有提供例子, 只能自己摸索着过河. 对于日期组件穿透样式,我们能…

收集了很久的全网好用的磁力搜索站列表分享

之前找资源的时候&#xff0c;收集了一波国内外大部分主流的磁力链接搜索站点。每一个站可能都有对应的优缺点&#xff0c;多试试&#xff0c;就能知道自己要哪个了。 全网好用的磁力链接 大部分的时候&#xff0c;我们用国内的就可以了&#xff0c;速度块&#xff0c;而且不…

Snappy使用

Snappy使用 Snappy是谷歌开源的压缩和解压的开发包&#xff0c;目标在于实现高速的压缩而不是最大的压缩 项目地址&#xff1a;GitHub - google/snappy&#xff1a;快速压缩器/解压缩器 Cmake版本升级 该项目需要比较新的cmake&#xff0c;CMake 3.16.3 or higher is requi…

51单片机第23步_定时器1工作在模式0(13位定时器)

重点学习51单片机定时器1工作在模式0的应用。 在51单片机中&#xff0c;定时器1工作在模式0&#xff0c;它和定时器0一样&#xff0c;TL1占低5位&#xff0c;TH1占高8位&#xff0c;合计13位&#xff0c;也是向上计数。 1、定时器1工作在模式0 1)、定时器1工作在模式0的框图…

8619 公约公倍

这个问题可以通过计算最大公约数 (GCD) 和最小公倍数 (LCM) 来解决。我们需要找到一个整数&#xff0c;它是 a, b, c 的 GCD 的倍数&#xff0c;同时也是 d, e, f 的 LCM 的约数。 以下是解决这个问题的步骤&#xff1a; 1. 计算 a, b, c 的最大公约数。 2. 计算 d, e, f 的最…

流处理系统对比:RisingWave vs ksqlDB

本文将从架构、部署与可扩展性、Source 和 Sink、生态系统与开发者工具几个方面比较 ksqlDB 和 RisingWave 这两款领先的流处理系统。 1. 架构 ksqlDB 是由 Confluent 开发和维护的流处理 SQL 引擎&#xff0c;专为 Apache Kafka 设计。它基于 Kafka Streams 构建&#xff0c;…

鸿蒙:路由Router原理

页面路由&#xff1a;在应用程序中实现不同页面之间的跳转和数据传递 典型应用&#xff1a;商品信息返回、订单等多页面跳转 页面栈最大容量为32个页面&#xff0c;当页面需要销毁可以使用router.clear()方法清空页面栈 router有两种页面跳转模式&#xff1a; router.pushUrl…

Golang 开发实战day15 - Input info

&#x1f3c6;个人专栏 &#x1f93a; leetcode &#x1f9d7; Leetcode Prime &#x1f3c7; Golang20天教程 &#x1f6b4;‍♂️ Java问题收集园地 &#x1f334; 成长感悟 欢迎大家观看&#xff0c;不执着于追求顶峰&#xff0c;只享受探索过程 Golang 开发实战day15 - 用户…

02归并排序——分治递归

02_归并排序_——分治_递归_ #include <stdio.h>void merge(int arr[], int l, int m, int r) {int n1 m -l 1;int n2 r -m;//创建临时数组int L[n1], R[n2];for(int i 0; i < n1; i){L[i] arr[l i];}for(int j 0; j < n2; j){R[j] arr[m 1 j];}int i …

OpenSSH RCE (CVE-2024-6387) | 附poc | 小试

Ⅰ 漏洞描述 OpenSSH 远程代码执行漏洞(CVE-2024-6387)&#xff0c;该漏洞是由于OpenSSH服务器 (sshd) 中的信号处理程序竞争问题&#xff0c;未经身份验证的攻击者可以利用此漏洞在Linux系统上以root身份执行任意代码。 Ⅱ 影响范围 8.5p1 < OpenSSH < 9.8p1 但OpenSS…

ghost恢复?电脑文件恢复如何操作?电脑数据恢复工具!5款!

在数字化时代&#xff0c;电脑数据的价值日益凸显。然而&#xff0c;数据丢失、误删、系统崩溃等问题时有发生&#xff0c;给个人和企业带来巨大损失。本文将为您详细介绍Ghost恢复方法&#xff0c;同时推荐五款高效的电脑数据恢复工具&#xff0c;助您轻松应对数据丢失的困扰。…