STL库 —— priority_queue 的编写

news2024/12/23 18:54:00

目录

一、 优先级队列的介绍

二、优先级队列的使用

2.1 建大堆 less

2.2 建小堆 greater

2.3 详解 greater 与 less

三、 priority_queue 的模拟实现 

3.1 编写框架 

3.2 编写简单函数

3.2 进堆 向上调整

3.3 出堆 向下调整

四、完整代码 


一、 优先级队列的介绍

1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的
2. 其内容类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。
3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。
4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:
empty():检测容器是否为空
size():返回容器中有效元素个数
front():返回容器中第一个元素的引用
push_back():在容器尾部插入元素

5. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。
6. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数 make_heap、push_heap 和 pop_heap 来自动完成此操作。

二、优先级队列的使用

优先级队列的传入参数有三个,分别是对象类型 T ,默认构造容器 Container , 比较方式  Compare ,从下图可以看出,后两个参数都有缺省值,当要改变堆中的比较方式时,要记得传入第二个模板参数!

2.1 建大堆 less

首先,优先级队列的首元素默认是最大的,如下图是默认情况下的对顶元素是堆中的最大值,库中默认缺省值为 less 。

2.2 建小堆 greater

但是,类似于 qsort 函数,可以提供特定的方式以达到特定的需求,如下,库中提供的 greater 可以使堆顶元素变为最小值:

除了上面实例化对象时的构造方式,可以在实例化对象时就传入参数:

vector<int> v = { 2, 9, 1, 6, 7, 4, 0 };	
priority_queue<int, vector<int>, greater<int>> pq2(v.begin(), v.end());

2.3 详解 greater 与 less

在C++中,std::greaterstd::less 实际上是函数对象(也称为仿函数或者functors),而非简单的函数。一个函数对象是任何提供了函数调用运算符(operator())的对象。
这意味着,对象行为类似于函数:可以通过提供参数列表并使用圆括号语法来"调用"它。

 下面直接来看一下 greater 与 less 的底层实现:

    template<class T>
	struct greater
	{
		bool operator()(T& left, T& right)
		{
			return left > right;
		}
	};

	template<class T>
	struct less
	{
		bool operator()(T& left, T& right)
		{
			return left < right;
		}
	};

这样对于实例化对象时传入的 greater 或 less 就有了比较清晰的认识,而这也是不需要传入参数的原因,它们压根就不是个函数,而只是个对 () 的操作符重载。

这里先提一下下面的向上调整:


可以看到这里类似使用函数调用,但其实是创建了匿名类。

三、 priority_queue 的模拟实现 

3.1 编写框架 

如下,首先搭建一个框架:

    template<class T>
	struct greater
	{
		bool operator()(T& left, T& right)
		{
			return left > right;
		}
	};

	template<class T>
	struct less
	{
		bool operator()(T& left, T& right)
		{
			return left < right;
		}
	};
	template <class T, class Container = std::vector<T>, class Compare = less<T> >
	class my_priority_queue
	{
	public:
		my_priority_queue()
		{
			_con();
		}
		void push(T x)
		{}
		void pop()
		{}
		size_t size()
		{}
		bool empty()
		{}
		// 堆顶元素不允许修改,因为:堆顶元素修改可以会破坏堆的特性
		const T& top() const
		{}
	private:
		Container _con;
	};

3.2 编写简单函数

从对 priority_queue 的介绍得知,有几个函数都是很好写的:

        size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
		// 堆顶元素不允许修改,因为:堆顶元素修改可以会破坏堆的特性
		const T& top() const
		{
			return _con.front();
		}

3.2 进堆 向上调整

但是, push 和 pop 会更复杂一些,这涉及到对堆内容的调整,调整的方法和 C语言 中堆的向上与向下调整算法大致相同,下面以 less 建大堆举例:

		void AdjustUp(int child)
		{
			int father = (child - 1) / 2;
			while (child > 0)
			{
				if (Compare()(_con[father], _con[child]))
				{
					swap(_con[child], _con[father]);
					child = father;
					father = (child - 1) / 2;
				}
				else
					return;
			}
		}

		void push(T x)
		{
			_con.push_back(x);
			AdjustUp(_con.size() - 1);
		}

暂时先组略的用调试的方法对照的看一下:

3.3 出堆 向下调整

		void AdjustDown()
		{
			int father = 0;
			int child = father * 2 + 1;
			while(child < _con.size())
			{	
				if (child + 1 < _con.size() && Compare()(_con[child], _con[child + 1])) 
                    child += 1;
				if (_con[father] < _con[child])
				{
					swap(_con[father], _con[child]);
					father = child;
					child = father * 2 + 1;
				}
				else
					return;
			}
		}
		void pop()
		{
			if (_con.empty()) return;

			swap(_con.front(), _con.back());
			_con.pop_back();
			AdjustDown();
		}

四、完整代码 

#include <iostream>
#include<vector>
using namespace std;
namespace Flash
{
	template<class T>
	struct greater
	{
		bool operator()(T& left, T& right)
		{
			return left > right;
		}
	};

	template<class T>
	struct less
	{
		bool operator()(T& left, T& right)
		{
			return left < right;
		}
	};

	template <class T, class Container = std::vector<T>, class Compare = less<T> >
	class my_priority_queue
	{
	public:
		my_priority_queue() : _con()
		{}
		void push(T x)
		{
			_con.push_back(x);
			AdjustUp(_con.size() - 1);
		}
		void pop()
		{
			if (_con.empty()) return;

			swap(_con.front(), _con.back());
			_con.pop_back();
			AdjustDown();
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
		// 堆顶元素不允许修改,因为:堆顶元素修改可以会破坏堆的特性
		const T& top() const
		{
			return _con.front();
		}
	private:
		void AdjustUp(int child)
		{
			int father = (child - 1) / 2;
			while (child > 0)
			{
				if (Compare()(_con[father], _con[child]))
				{
					swap(_con[child], _con[father]);
					child = father;
					father = (child - 1) / 2;
				}
				else
					return;
			}
		}
		void AdjustDown()
		{
			int father = 0;
			int child = father * 2 + 1;
			while(child < _con.size())
			{	
				if (child + 1 < _con.size() && Compare()(_con[child], _con[child + 1])) child += 1;
				
				if (_con[father] < _con[child])
				{
					swap(_con[father], _con[child]);
					father = child;
					child = father * 2 + 1;
				}
				else
					return;
			}
		}
	private:
		Container _con;
	};
	void test_push()
	{
		my_priority_queue<int> mpq;
		mpq.push(3);
		mpq.push(2);
		mpq.push(5);
		mpq.push(1);
		mpq.push(4);
	}
	void test_pop()
	{
		my_priority_queue<int> mpq;
		mpq.push(3);
		mpq.push(2);
		mpq.push(5);
		mpq.push(1);
		mpq.push(4);
		while (!mpq.empty())
		{
			cout << mpq.top() << endl;
			mpq.pop();
		}
	}
}

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

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

相关文章

【Python系列】非异步方法调用异步方法

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

浅谈数据结构---红黑树、二叉树

红黑树简介 红黑树&#xff1a;在本质上还是二叉树&#xff0c;是一种高效的查找树。 特点 一边的数比另一边的数高太多时&#xff0c;自动旋转平衡 当数据量比较大时&#xff0c;层级比较多&#xff0c;查询效率低 如下图所示&#xff1a; 如果一边的数比另一边高太多时&…

AI智能电销机器人是什么?能给我们带来哪些便利?

科技的飞速发展&#xff0c;让很多“懒人”的幻想变成了现实&#xff0c;越来越多的人工智能产品被发明出来甚至完全替代日常生活中的工作。比如在电销行业&#xff0c;很多企业选择AI智能电销机器人进行外呼。那么你了解多少AI智能电销机器人呢&#xff1f;和小编kelaile520一…

前端js控制元素移动

背景 页面中有多个表格&#xff0c;每个表格中均有一从右到左匀速移动的元素&#xff0c;随着元素移动需要在表格中增减数据&#xff0c;由于使用css3动画无法捕捉元素移动位置&#xff0c;所以这里采用js控制dom的写法 解决办法 最终代码放在文章的最后&#xff0c;各位看官…

热塑性聚氨酯TPU的特性有哪些?UV胶水能够粘接热塑性聚氨酯TPU吗?又有哪些优势呢?

热塑性聚氨酯&#xff08;Thermoplastic Polyurethane&#xff0c;TPU&#xff09;是一种具有多种优异性能的弹性塑料&#xff0c;广泛用于各种应用领域。以下是TPU的一些主要特性&#xff1a; 弹性和柔软性&#xff1a; TPU具有良好的弹性和柔软性&#xff0c;能够在受力后迅速…

现在给政府机关医院学校部队供货的方式有哪些?

给政府机关、医院、学校和部队供货的方式主要包括以下几种&#xff1a; 直接采购&#xff1a;政府机关、医院、学校和部队通过招标或直接与供应商进行谈判&#xff0c;确定采购的产品和价格。这种方式常见于大宗或重要物资的采购&#xff0c;能够确保采购过程的透明度和公正性…

林草资源管理系统:构筑绿色长城,守护自然之美

在全球气候变化和生态环境恶化的背景下&#xff0c;森林和草原资源的保护、恢复和合理利用显得尤为重要。林草资源管理系统的建立&#xff0c;旨在通过现代信息技术手段&#xff0c;提升林草资源管理的效率和质量&#xff0c;确保自然资源的可持续发展。 项目背景 森林和草原…

Nacos—配置管理

简介&#xff1a; Nacos是阿里巴巴开发的&#xff0c;它旨在帮助用户更敏捷和容易地构建、交付和管理微服务平台。Nacos的主要功能和特性包括&#xff1a; 动态服务发现。Nacos支持基于DNS和RPC的服务发现&#xff0c;允许服务提供者和消费者之间的高效交互。动态配置管理。…

2024华中杯ABC题完1-3小问py代码+完整思路16页+后续参考论文

A题太阳能路灯光伏板朝向问题 &#xff08;完整版获取在文末&#xff09; 第1小问&#xff1a;计算每月15日的太阳直射强度和总能量 1. 理解太阳直射辐射和光伏板的关系**&#xff1a;光伏板接收太阳辐射并转化为电能&#xff0c;直射辐射对光伏板的效率影响最大。 2. 收集数…

线程互斥,线程安全和线程同步

多线程的基本代码编写步骤 1.创建线程pthread_create() 2.终止线程的三种方法。线程取消pthread_cancel(一般在主线程取消)&#xff0c; 线程终止pthread_exit(在其他线程执行)&#xff0c; 或者使用线程返回return 3.线程等待pthread_join 需要等待的原因是 1.已经退出的线程…

Java程序生成可执行的exe文件 详细图文教程

1.Java编辑器&#xff0c;如&#xff1a;idea、eclipse等&#xff0c;下载地址&#xff1a;IntelliJ IDEA: The Capable & Ergonomic Java IDE by JetBrainshttps://www.jetbrains.com/idea/2.exe4j&#xff0c;下载地址&#xff1a;ej-technologies - Java APM, Java Prof…

spring 集成 mybatis

spring 集成 mybatis 1、spring对junit的支持1.1、对junit4的支持1.2 对junit5的支持 2、Spring6集成MyBatis3.52.1 实现步骤2.2 实现 1、spring对junit的支持 1.1、对junit4的支持 依赖 <?xml version"1.0" encoding"UTF-8"?> <project xml…

基于XML配置bean(一)

文章目录 1.获取bean的两种方式1.通过id获取bean&#xff08;前面用过&#xff09;2.通过类型获取bean&#xff08;单例时使用&#xff09;1.案例2.代码1.beans.xml2.SpringBeanTest.java3.结果 3.注意事项 2.三种基本依赖注入方式1.通过属性配置bean&#xff08;前面用过&…

图与图搜索算法

图搜索算法是一个非常重要的概念&#xff0c;它是计算机科学中图论和算法设计的基础部分。在开始讨论图搜索算法之前&#xff0c;我们需要先理解什么是图以及图的基本结构。 什么是图&#xff1f; 图&#xff08;Graph&#xff09;是一种非线性数据结构&#xff0c;它由一组点…

通过vue完成表格数据的渲染展示和vue的生命周期及小结

案例 通过vue完成表格数据的渲染展示 把视图区展示的数据 死数据替换掉 从vue的数据模型中读取 展示在视图区 vue中的数据 模型是js中的自定义类型 形成的数组 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8">&l…

Mathorcup 甲骨文识别

本资源主要包含第2-4问&#xff0c;第一问直接使用传统图像处理即可&#xff0c;需要有很多步骤&#xff0c;这一步大家自己写就行。 2 第2问&#xff0c;甲骨文识别 2.1 先处理源文件 原文件有jpg和json文件&#xff0c;都在一个文件夹下&#xff0c;需要对json文件进行处理…

Python路面车道线识别偏离预警

程序示例精选 Python路面车道线识别偏离预警 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《Python路面车道线识别偏离预警》编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;易…

牛客Linux高并发服务器开发学习第三天

静态库的使用(libxxx.a) 将lession04的文件复制到lession05中 lib里面一般放库文件 src里面放源文件。 将.c文件转换成可执行程序 gcc main.c -o app main.c当前目录下没有head.h gcc main.c -o app -I ./include 利用-I 和head所在的文件夹&#xff0c;找到head。 main.c…

针对springcloud gateway 跨域问题解决方案

springcloud gateway版本 <spring-boot.version>2.3.3.RELEASE</spring-boot.version> <spring-cloud.version>Hoxton.SR8</spring-cloud.version>跨域问题说明 application:1 Access to XMLHttpRequest at https://xxxxxxxxxx from origin http://l…

<计算机网络自顶向下> 可靠数据传输的原理(未完成)

可靠数据传输&#xff08;rdt&#xff1a;Reliable Data Transfer&#xff09;的原理 rdt在应用层&#xff0c;传输层和数据链路层都很重要是网络TOP10问题之一信道的不可靠特点决定了可靠数据传输rdt的复杂性rdt_send: 被上层&#xff08;如应用层&#xff09;调用&#xff0…