priority_queue简单实现(优先级队列)(c++)

priority_queue

  • priority_queue介绍
  • 逻辑实现
    • 框架
    • 调整算法
      • adjust_up()
      • adjust_down()
    • 仿函数/比较函数
    • 仿函数特性
  • 构造函数
    • 迭代器区间构造
  • 完整优先级队列代码

priority_queue介绍

pri_que是一个容器适配器,它的底层是其他容器,并由这些容器再封装而来。类似于heap的结构。默认为大堆。
在这里插入图片描述

逻辑实现

框架

namespace xty 
{
	template<class T, class Container = vector<T>, class Compare = less<T>>
	class priority_queue
	{

		bool empty()
		{
			return _con.empty();
		}

		size_t size()
		{
			return _con.size();
		}

		const T& top()
		{
			return _con.front();
		}


		void push(const T& x)
		{
			_con.push_back(x);
			adjust_up(_con.size() - 1);
		}

		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjust_down(0);
		}

	private:
		Container _con;
	};
}

调整算法

因为优先级队列是以堆为结构实现的,因此插入删除要保持堆的结构,需要adjust_up()和adjust_down()两个算法。
建堆算法详细参考

adjust_up()

向上调整,由堆底一直调整到堆顶。

		void adjust_up(int child)
		{
			int parent = (child - 1) / 2;

			while (child > 0)
			{
				if (_con[child] > _con[parent])
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

adjust_down()

向下调整,由堆顶一直向下调整直到叶子。

		void adjust_down(int parent)
		{
			size_t child = 2 * parent + 1;
			while (child < _con.size())
			{
				if (child + 1 < _con.size() && _con[child + 1] > _con[child])
				{
					child++;
				}
				if (_con[child] > _con[parent])
				{
					swap(_con[child], _con[parent]);
					parent = child;
					child = 2 * parent + 1;
				}
				else
				{
					break;
				}
			}
		}

仿函数/比较函数

我们观察到库的模板参数给了三个,其中第一个参数是数据类型,第二个参数是模板容器,第三个参数就是仿函数(用户可以自己制定比较规则!),默认为大堆less。

template<class T, class Container = vector<T>, class Compare = less<T>>

接下来我们实现一个比较类:

	template<class T>
	struct less
	{
		bool operator() (const T& x, const T& y)
		{
			return x > y;
		}
	};

	template<class T>
	struct grater
	{
		bool operator() (const T& x, const T& y)
		{
			return x < y;
		}
	};

然后我们微调调整函数的逻辑将if的内容改成比较函数:
因为使用方法酷似函数,因此它叫仿函数 !

		void adjust_up(int child)
		{
			Compare com;  //实例化比较函数
			int parent = (child - 1) / 2;

			while (child > 0)
			{
				if (com(_con[child], _con[parent]))
				/*if (_con[child] > _con[parent])*/
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void adjust_down(int parent)
		{
			Compare com;  //实例化比较函数
			size_t child = 2 * parent + 1;
			while (child < _con.size())
			{
				if (child + 1 < _con.size() && com(_con[child + 1], _con[child]))
				{
					child++;
				}
				if (com(_con[child], _con[parent]))
				{
					swap(_con[child], _con[parent]);
					parent = child;
					child = 2 * parent + 1;
				}
				else
				{
					break;
				}
			}
		}

仿函数特性

有了仿函数的功能后,我们可以自己定义比较类型,使程序设计更加灵活。

看下面一段代码:

	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)
		{
			_cout << d._year << "-" << d._month << "-" << d._day;
			return _cout;
		}

	private:
		int _year;
		int _month;
		int _day;
	};


	void test_priority_queue2()
	{
		// 大堆,需要用户在自定义类型中提供<<的重载
		//priority_queue<Date> q1;
		priority_queue<Date, vector<Date>, greater<Date>> q1;
		q1.push(Date(2018, 10, 29));
		q1.push(Date(2018, 10, 30));
		q1.push(Date(2018, 10, 28));
		cout << q1.top() << endl;
	}

首先这段测试代码结果是唯一的:
在这里插入图片描述
而如果我们增加另一种格式的代码呢?

	class PDateLess
	{
	public:
		bool operator()(const Date* p1, const Date* p2)
		{
			return *p1 < *p2;
		}
	};

	class PDateGreater
	{
	public:
		bool operator()(const Date* p1, const Date* p2)
		{
			return *p1 > *p2;
		}
	};
	void test_priority_queue2()
	{
		//priority_queue<Date*, vector<Date*>, PDateLess> q2;
		priority_queue<Date*, vector<Date*>, PDateGreater> q2;
		q2.push(new Date(2018, 10, 29));
		q2.push(new Date(2018, 10, 30));
		q2.push(new Date(2018, 10, 28));
		cout << *(q2.top()) << endl;
	}

这段代码如果不写仿函数,结果是不唯一的,因为比较的是指针,重写仿函数后,答案就唯一了!!可以看见,仿函数可以使我们比较数据更加灵活!

构造函数

显然我们没有写构造函数,程序并没有报错,是因为:

  • 我们不写构造函数,编译器会默认生成一个。而成员函数是自定义类型,会调用自定义类型的构造函数,所以程序没有问题运行。
  • 当我们写了构造函数之后,编译器就不会再默认生成了,需要我们自己写。

迭代器区间构造

因为自己显示写了构造函数,编译器不再默认生成默认构造函数,需要自己再显示补一个默认构造!

		//默认构造
		priority_queue(){}
		
		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
		{
			Container _con;
			while (first!= last)
			{
				push(*first);
				first++;
			}
		}

完整优先级队列代码

namespace xty 
{
	template<class T>
	struct less
	{
		bool operator() (const T& x, const T& y)
		{
			return x > y;
		}
	};

	template<class T>
	struct grater
	{
		bool operator() (const T& x, const T& y)
		{
			return x < y;
		}
	};

	template<class T, class Container = vector<T>, class Compare = less<T>>
	class priority_queue
	{
	public:
		void adjust_up(int child)
		{
			Compare com;  //实例化比较函数
			int parent = (child - 1) / 2;

			while (child > 0)
			{
				if (com(_con[child], _con[parent]))
				/*if (_con[child] > _con[parent])*/
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void adjust_down(int parent)
		{
			Compare com;  //实例化比较函数
			size_t child = 2 * parent + 1;
			while (child < _con.size())
			{
				if (child + 1 < _con.size() && com(_con[child + 1], _con[child]))
				{
					child++;
				}
				if (com(_con[child], _con[parent]))
				{
					swap(_con[child], _con[parent]);
					parent = child;
					child = 2 * parent + 1;
				}
				else
				{
					break;
				}
			}
		}


		bool empty()
		{
			return _con.empty();
		}

		size_t size()
		{
			return _con.size();
		}

		const T& top()
		{
			return _con.front();
		}


		void push(const T& x)
		{
			_con.push_back(x);
			adjust_up(_con.size() - 1);
		}

		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjust_down(0);
		}

		priority_queue(){}
		
		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
		{
			Container _con;
			while (first!= last)
			{
				push(*first);
				first++;
			}
		}


	private:
		Container _con;
	};
}

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

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

相关文章

Win10之bandicam录音无声音问题(七十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

分布式进阶-链路追踪SpringCloudSleuth、Zipkin【实战篇】

一、前言 我们在使用微服务的时候&#xff0c;往往设计到各个微服务之间的调用&#xff0c;肯定会存在深度的调用链路&#xff0c;如果出现BUG或者异常&#xff0c;就会让问题定位和处理效率非常低。 有了Sleuth &#xff0c;就可以帮助我们记录、跟踪应用程序中的请求和操作。…

C++:哈希表的模拟实现

文章目录 哈希哈希冲突哈希函数 解决哈希冲突闭散列&#xff1a;开散列 哈希 在顺序结构和平衡树中&#xff0c;元素的Key和存储位置之间没有必然的联系&#xff0c;在进行查找的时候&#xff0c;要不断的进行比较&#xff0c;时间复杂度是O(N)或O(logN) 而有没有这样一种方案…

数据库基本操作-----数据库用户管理和授权

一、数据库用户管理 1&#xff0e;新建用户 CREATE USER 用户名来源地址 [IDENTIFIED BY [PASSWORD] 密码];‘用户名’&#xff1a;指定将创建的用户名 ‘来源地址’&#xff1a;指定新创建的用户可在哪些主机上登录&#xff0c;可使用IP地址、网段、主机名的形式&#xff0c…

linux下流媒体压力测试工具的使用

前言 因为领导要求做linux的推拉流时服务器压力测试&#xff0c;于是在网上找了找。一顿操作下来&#xff0c;发现很多软件盗用一款名为srs-bench的开源软件。 该代码仓库有详细的使用说明&#xff0c;而且可以在issues中找到可能会遇到的问题的解决办法 需要下载该仓库的源…

C# Onnx 百度PaddleSeg发布的实时人像抠图PP-MattingV2

目录 效果 模型信息 项目 代码 下载 效果 图片源自网络侵删 模型信息 Inputs ------------------------- name&#xff1a;img tensor&#xff1a;Float[1, 3, 480, 640] --------------------------------------------------------------- Outputs -----------------…

ZLMediaKit安装配置和推拉流

一、ZLMediaKit 库简介 ZLMediaKit 是一个基于 C11 的高性能运营级流媒体服务框架 官方写的项目特点&#xff1a; 基于 C11 开发&#xff0c;避免使用裸指针&#xff0c;代码稳定可靠&#xff0c;性能优越。 支持多种协议(RTSP/RTMP/HLS/HTTP-FLV/Websocket-FLV/GB28181/MP…

栈的生长方向不总是向下

据我了解&#xff0c;栈的生长方向向下&#xff0c;内存地址由高到低 测试 windows下&#xff1a; 符合上述情况 测试Linux下&#xff1a; 由此可见&#xff0c;栈在不同操作系统环境下&#xff0c;生长方向不总是向下

【Python】Vscode解决Python中制表符和空格混用导致的缩进问题

【Python】Vscode解决Python中制表符和空格混用导致的缩进问题 文章目录 【Python】Vscode解决Python中制表符和空格混用导致的缩进问题1. 问题来源2. 解决Reference 1. 问题来源 在python中使用缩进来进行代码块的分区&#xff0c;通常来说python的一个缩进包含4个空格&#…

不存在类型变量 A, T 的实例,使 Collector<T, A, List<T>> 符合 Supplier<R>

报错信息 原因: 不存在类型变量 A, T 的实例&#xff0c;使 Collector<T, A, List<\T>> 符合 Supplier<\R> 来源 测试Stream流的map方法&#xff0c;做算法习惯基本类型定义数组。 map方法:Stream API的一部分。允许以一种声明式的方式处理数据&#xff0c…

nodejs搭建本地服务

前端开发时想自己有个本地服务如下操作直接上干货 1.在桌面上直接在powerShell 输入命令行 npm install -g express-generator 然后 npm install -g express 然后新建一个例如server的文件夹 在powerShell执行 express myStudy -e 端口号默认是3000 直接在地址栏输入 http://…

Windows 7 连接 Windows 10 共享打印机,Windows 无法连接打印机,操作失败,错误为0x0000011b 的终极解决办法

Windows 7 连接 Windows 10 共享打印机出现错误 0x000001b&#xff0c;建议不要通过卸载Windows10系统的KB5005565安全更新来解决该问题&#xff08;犹如削足适履&#xff09;&#xff0c;正确的处理方法是手工添加一个本地打印机&#xff0c;本方法是安全可靠的。本文详述了该…

枚举 蓝桥oj DNA序列修正

题目详情&#xff1a; 简单翻译&#xff1a; 主要思路&#xff1a; 1 本题采用贪心思路&#xff0c;要使调整次数最少&#xff0c;就是尽量交换两个碱基对&#xff0c;而不是单个替换&#xff0c;因为本题已经说明只能每个碱基对只能交换一次&#xff0c;所以不考虑A与B交换再…

NC65 修改元数据字段长度

NC65 修改元数据字段长度&#xff0c;执行下面sql&#xff0c;执行完后需要重启NC服务才生效。 --属性 update md_property set attrlength 200 where name fphm and classidece96dd8-bdf8-4db3-a112-9d2f636d388f ;--列 update md_column set columnlength 200 where tab…

远程命令执行漏洞原理,以及防护绕过方式

一、背景 RCE(Remote Command /Code Execute) 远程代码执行漏洞 通过PHP代码注入、Java代码注入等方式连接程序中预留的后门或接口从而进行远程命令执行&#xff0c;达到对服务器的控制。 为什么会出现远程代码执行漏洞呢&#xff1f; Web应用有时需要调用执行一些系统命令函数…

YOLOv5 环境搭建

YOLOv5 环境搭建 flyfish 环境 Ubuntu20.04 驱动、CUDA Toolkit、cuDNN、PyTorch版本对应 1 NVIDIA驱动安装 在[附加驱动界]面安装驱动时&#xff0c;需要输入安全密码&#xff0c;需要记下&#xff0c;后面还需要输入这个密码 重启之后有的机器会出现 perform mok manage…

C2039 编译clr工程报错

在编译clr工程的时候出现错误 错误提示如下 出现上述情况的代码文件 crl头文件VideoPlayerCLRDLL.h 被crl引用的头文件PlayerEnterPort.h 在上述情况下&#xff0c;编译clr工程会编译opengl_player.h头文件中的内容&#xff0c;但在clr工程中不认识std::mutex&#xff0c…

设计模式篇---外观模式

文章目录 概念结构实例总结 概念 外观模式&#xff1a;为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口&#xff0c;这个接口使得这一子系统更加容易使用。 外观模式引入了一个新的外观类&#xff0c;它为多个业务类的调用提供了一个统一的入口。主要优点…

Leetcode—8.字符串转换整数(atoi)【中等】

2023每日刷题&#xff08;三十七&#xff09; Leetcode—8.字符串转换整数&#xff08;atoi&#xff09; 算法思想 参考k神的题解 实现代码 int myAtoi(char* s) {int len strlen(s);if(len 0) {return 0;}int boundary INT_MAX / 10;int i 0, ans 0;while(s[i] ) …

Java异常处理机制

Java异常处理机制 一、异常概述与异常体系结构异常概述Error示例代码&#xff1a;Exception示例代码&#xff1a;异常体系结构Error和Exception的区别:异常分类检查异常非检查异常Why:为什么有非检查异常&#xff1f;Where:非检查异常有哪些&#xff1f;Exception异常划分运行时…