priority_queue的模拟实现

news2024/11/17 0:47:24

前言

        优先级队列听名字好像与队列有关,但是实际上,与队列没有很多关系,它也是容器适配器,是通过vector来适配的,但是里面又加入了堆的调整算法。跟栈和队列又有一些不同,了解它的实现对于我们更好的掌握它是有一定的帮助的。 

目录

1.完整代码

2.向上调整算法

3.向下调整算法

4.仿函数

5.测试代码 


1.完整代码

namespace qyy
{
	//less是小于,但是确默认生成的是大堆
	template<class T,class container = vector<T>,class compare = less<T>>
	class priority_queue
	{
	public:
		//向下调整算法
		void AdjustDown(int root,int Size)//闭区间
		{
			int chird = root * 2 + 1;
			while (chird<= Size)//孩子到最后一个叶子节点就可以结束了
			{
				//确定孩子中较大的哪个
				if (chird+ 1 <= Size&& _com(_con[chird] , _con[chird+1])  )//chird+1要在数组的范围内比较才有意义
					++chird;//找出孩子中值大的那个,然后进行比较
				//比较root和chird
				//if (pq[chird] > pq[root])//交换
				if(  _com(_con[root] , _con[chird])  )
				{
					swap(_con[chird], _con[root]);
					//迭代往后继续比较
					root = chird;
					chird = root * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}
		//向上调整算法
		void AdjustUp(int chird)
		{
			int parent = (chird - 1) / 2;
			while (parent>= 0)//继续调整
			{
				//if (pq[parent] < pq[chird])//父亲比孩子小
				if(_com(_con[parent],_con[chird]))
				{
					//交换
					swap(_con[parent], _con[chird]);
					//迭代继续
					chird = parent;
					parent = (chird - 1) / 2;
				}
				else 
				{
					break;//不要交换直接结束程序
				}
			}
		}
		void push(const T& data)
		{
 			_con.push_back(data);//先尾插
			//在向上调整
			AdjustUp(_con.size()-1);
		}
		void pop()
		{
			//先将最大和末尾的进行交换
			swap(_con[0], _con[_con.size() - 1]);
			//删除队尾元素
			_con.pop_back();
			//向下调整
			AdjustDown(0,_con.size()-1);
		}
		size_t size()
		{
			return _con.size();
		}
		bool empty()
		{
			return _con.empty();
		}
		T& top()
		{
			return _con.front();
		}
	private:
		container _con;
		compare _com;
	};
}
//仿函数 仿函数又叫函数对象
namespace qyy
{
	template<class T>
	struct less
	{
		bool operator()(const T& num1,const T& num2)
		{
			return num1 < num2;
		}
	};
	template<class T>
	struct greater
	{
		bool operator()(const T& num1, const T& num2)
		{
			return num1 > num2;
		}
	};
}

        这里的底层容器和仿函数都给了缺省参数,因为默认是大堆所以就给缺省的模板参数,也就是泛型编程。 

2.向上调整算法

        向上调整算法是在建堆时进行使用的,就是为了保证堆的性质,其实在物理结构上堆是一颗满二叉树 且分为大堆和小堆,大堆就是堆顶的数据大于堆底的数据,反映到二叉树上面就是,根节的值点大于左右子树,整个数都满足这个规律就是大堆了,反之如果根节点的值小于左右子树,且整个树都满足这个规律就是小堆了。如图:

因为堆是借助数组实现的所以看起来是这样的,其实可以看出下面这样:

 

        上面是一个大根堆,那么堆的向上调整算法是如何实现的呢?我们一起向下看:

          

         代码实现如下:

	    //向上调整算法
		void AdjustUp(int chird)
		{
			int parent = (chird - 1) / 2;
			while (parent>= 0)//继续调整
			{
				//if (pq[parent] < pq[chird])//父亲比孩子小
				if(_com(_con[parent],_con[chird]))
				{
					//交换
					swap(_con[parent], _con[chird]);
					//迭代继续
					chird = parent;
					parent = (chird - 1) / 2;
				}
				else 
				{
					break;//不要交换直接结束程序
				}
			}
		}

        优先级队列push数据的时候是先push数据到vector中,然后使用向上调整算法来维持堆。 

3.向下调整算法

        在优先级队列pop数据的时候是先将堆顶的元素与堆底的元素交换数据,然后在删除堆底的元素,调用向下调整算法来维持堆的特性,因为优先级队列始终出队的是优先级最高的元素

        向下调整算法首先从根节点开始,如果是建大堆,就将根节点与左右节点中较大的那个比较,如果左右节点中值较大的那个大于根节点的值就交换左右节点与根节点,更新根节点和左右节点的值,继续比较,知道比较的叶子节点的下标大于数组的值,我这样将可能太抽象了,就拿这组已经调整好了的数据来看看吧,

此时pop数据,先交换9和6,然后删除调数组末尾的9,从数组开头开始进行向下调整。如图:

 

        实现代码:

	    //向下调整算法
		void AdjustDown(int root,int Size)//闭区间
		{
			int chird = root * 2 + 1;
			while (chird<= Size)//孩子到最后一个叶子节点就可以结束了
			{
				//确定孩子中较大的哪个
				if (chird+ 1 <= Size&& _com(_con[chird] , _con[chird+1])  )//chird+1要在数组的范围内比较才有意义
					++chird;//找出孩子中值大的那个,然后进行比较
				//比较root和chird
				//if (pq[chird] > pq[root])//交换
				if(  _com(_con[root] , _con[chird])  )
				{
					swap(_con[chird], _con[root]);
					//迭代往后继续比较
					root = chird;
					chird = root * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}

 

4.仿函数

        仿函数也叫函数对象,这里我们实现的优先级队列,不管建大根堆还是小根堆,都只能实现一份,要是再去实现另一种的话如果在写一份相同的代码,只是比较的逻辑相反那么代码的冗余度就会很高,所以这里提供了第三个模板参数,用来解决这个问题。

template<class T,class container = vector<T>,class compare = less<T>> 

        我们在实现调整算法的时候将需要比较大小的地方单独拎出来,用第三个模板参数去实例化出一个对象,然后通过这个对象调用operator() 来实现比较大小,如果我们传给模板的是比较小于为真的对象重载的operator(),那么就是数字大的优先级高,反之则相反,这里其实有个坑与正常的比较大小是相反的,至于为了写出这样的代码,这得问制定标准的大师了。正所谓前任挖坑后人跳坑。

        代码如下:

//仿函数 仿函数又叫函数对象
namespace qyy
{
	template<class T>
	struct less//比较大于
	{
		bool operator()(const T& num1,const T& num2)
		{
			return num1 < num2;
		}
	};
	template<class T>
	struct greater//比较小于
	{
		bool operator()(const T& num1, const T& num2)
		{
			return num1 > num2;
		}
	};
}

注意一般成员都是公有的采用struct定义类,如果成员一些公有一些私有采用class定义。

在使用STL中的sort时,默认排序排的都是升序,如果想要排降序就需要给它的缺省参数传一个仿函数,一般greater是排升序的,less是排降序的。

例如:

void test()
{
	vector<int>v1;
	v1.push_back(1);//对vector进行排序
	v1.push_back(6);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(5);
	v1.push_back(7);
	v1.push_back(4);
	greater<int>gt;//定义一个函数对象在进行传参
	sort(v1.begin(), v1.end(),gt);
	for (auto& e : v1)
		cout << e << " ";
	cout << endl;
	sort(v1.begin(), v1.end(),less<int>());//直接调用匿名对象传参,进行排序
	for (auto& e : v1)
		cout << e << " ";
    //两个效果相同但是调用匿名对象更方便一点
}

 

5.测试代码 

void TestPriorityQueue()
{
	qyy::priority_queue<int,vector<int>,greater<int>> it;//用优先级队列创建变量
	it.push(1);//入队
	it.push(3);
	it.push(4);
	it.push(9);
	it.push(2);
	it.push(7);
	it.push(5);
	it.push(6);
	while (!it.empty())//队列不为空
	{
		cout << it.top()<<"  ";//获取堆顶元素
		it.pop();//出队
		//优先级队列pop数据的时候会将优先级高的数据先出队,它的pop和stack与queue的pop不同。
	}
}

 

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

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

相关文章

新手上路,安全驾驶,做行车安全的第一责任人

目录 一、生活与汽车二、树立安全意识三、掌握驾驶经验四、参考材料 道路千万条&#xff0c;安全第一条&#xff0c;行车不规范&#xff0c;亲人两行泪。 ——《流浪地球》 一、生活与汽车 开车是为了节省在路途上花费的时间&#xff0c;片面的追求交通效率会引发交通安全问题&…

day8 栈顶的种类与应用

目录 多寄存器访问指令与寻址方式 多寄存器内存访问指令 多寄存器内存访问指令的寻址方式 ​编辑 栈的种类与使用 栈的概念 栈的分类 栈的应用举例 叶子函数的调用过程举例 多寄存器访问指令与寻址方式 多寄存器内存访问指令 MOV R1, #1 MOV R2, #2 MOV R3, #3 MOV R…

Redis 持久化存储机制:RDB 和 AOF

Redis&#xff08;Remote Dictionary Server&#xff09;是一个高性能的键值存储系统&#xff0c;它可以将数据存储在内存中以实现快速访问。为了保持数据的持久性&#xff0c;Redis 提供了两种数据持久化方法&#xff1a;RDB 和 AOF。 RDB&#xff08;Redis Database&#xff…

spring源码-代码的特殊写法

spring源码-代码的特殊写法 前言 在阅读spring源码中&#xff0c;可能会有很多种代码写法在工作中都没遇见过&#xff0c;阅读起来有一定的难度&#xff0c;在本文中&#xff0c;我会把我认为有难度的代码写法拿出来&#xff0c;并举例子说明清楚&#xff0c;方便大家阅读并理…

股价暴涨59%后,美股二手车平台Carvana在短期内还会进一步上涨?

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 Carvana(CVNA)股票在财报发布近一个月后又重新开始出现了上涨。 仅6月9日就上涨了59%。 相对于纳斯达克综合指数的上涨幅度&#xff0c;Carvana今年迄今为止的上涨幅度已经比纳斯达克综合指数高出了约400%。 Carvana最…

RabbitMQ - 死信队列,延时队列

Time-To-Live and Expiration — RabbitMQ 一、死信队列 Dead Letter Exchanges — RabbitMQ 死信队列&#xff1a; DLX 全称&#xff08;Dead-Letter-Exchange&#xff09;,称之为死信交换器&#xff0c;当消息变成一个死信之后&#xff0c;如果这个消息所在的队列存在x-d…

全球、全国遥感土地利用数据产品下载(1m、10m、30m分辨率,内含链接与详细教程)

土地利用/覆被数据能够获取地表覆被信息&#xff0c;同时也是地球系统科学学科的基础数据&#xff08;如生态、水文、地质等&#xff09;吗&#xff0c;目前&#xff0c;基于遥感生成的土地利用/覆被数据产品比较多样&#xff0c;本文整理了目前应用比较多的7种数据产品进行介绍…

Hazel游戏引擎(007)Premake

文中若有代码、术语等错误&#xff0c;欢迎指正 文章目录 前言操作步骤premake写lua脚本文件执行premake.exe文件效果 前言 此节目的 由于之前配置VS项目各项属性需要根据不同平台手动一个一个设置&#xff0c;很麻烦&#xff0c;缺乏灵活性。 用lua脚本配置项目属性&#xff0…

基于Java+SpringBoot的鞋类商品购物商城系统设计与实现

博主介绍&#xff1a;✌擅长Java、微信小程序、Python、Android等&#xff0c;专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案…

业务部门的通病:想搞了大而全的软件

业务部门的通病&#xff1a;想搞个大而全的软件 怎么样评价软件功能的价值重要性&#xff1f; 软件的消耗成本是惊人的 中小企业一定要约束需求 做SaaS的香港上市公司有赞&#xff08;做商城软件&#xff09; 10年了还在亏损 趣讲大白话&#xff1a;大而全的功能是陷阱 【趣讲信…

Geek-PC项目 文档

一款后台管理项目 - React-geek-PC 项目介绍 ● 项目功能演示 - 登录、退出 - 首页 - 内容&#xff08;文章&#xff09;管理&#xff1a;文章列表、发布文章、修改文章● 技术 - React 官方脚手架 create-react-app - react hooks - 状态管理&#xff1a;mobx - UI 组件库…

ESP32网络应用 -- ESP32-S3在STA模式下创建TCP-CLIENT应用程序

在ESP32-S3初始化为Station模式并且成功获取IP地址后,说明ESP32-S3芯片的底层设施已经具备Wi-Fi网络通信能力,但在实际的应用场景里面,仅仅建立数据链路层,还是不能够满足应用程序的数据通信需求。 TCP/IP是一种使用广泛的网络传输协议,网络上并不缺乏关于TCP/IP的具体原…

Atcoder Beginner Contest 304——A-D题讲解

蒟蒻来讲题&#xff0c;还望大家喜。若哪有问题&#xff0c;大家尽可提&#xff01; Hello, 大家好哇&#xff01;本初中生蒟蒻讲解一下AtCoder Beginner Contest 304这场比赛的A-D题&#xff01; A - First Player 题目描述 Problem Statement There are N N N people nu…

sequence2sequence

1. 基本模型 所谓的Seq2seq模型从字面上理解很简单&#xff0c;就是由一个序列到另一个序列的过程(比如翻译、语音等方面的应用)&#xff1a; 那么既然是序列模型&#xff0c;就需要搭建一个RNN模型(神经单元可以是GRU模型或者是LSTM模型) 下面两篇文章提出了这样的seq2seq的模…

NVM安装教程

我是小荣&#xff0c;给个赞鼓励下吧&#xff01; NVM安装教程 简介 nvm 是node.js的版本管理器&#xff0c;设计为按用户安装&#xff0c;并按 shell 调用。nvm适用于任何符合 POSIX 的 shell&#xff08;sh、dash、ksh、zsh、bash&#xff09;&#xff0c;特别是在这些平台…

ChatGPT 五个写论文的神技巧,让你的老师对你刮目相看!

导读&#xff1a;ChatGPT这款AI工具在推出两个月内就累积了超过1亿用户。我们向您展示如何使用ChatGPT进行写作辅助&#xff0c;以及其他一些有用的写作技巧。 本文字数&#xff1a;2000&#xff0c;阅读时长大约&#xff1a;12分钟 ChatGPT这款AI工具在推出两个月内就累积了超…

【Java|golang】2460. 对数组执行操作

给你一个下标从 0 开始的数组 nums &#xff0c;数组大小为 n &#xff0c;且由 非负 整数组成。 你需要对数组执行 n - 1 步操作&#xff0c;其中第 i 步操作&#xff08;从 0 开始计数&#xff09;要求对 nums 中第 i 个元素执行下述指令&#xff1a; 如果 nums[i] nums[i…

物联网Lora模块从入门到精通(三)按键的读取与使用

一、前言 在Lora例程中&#xff0c;为我们提供了三个按键标志位&#xff0c;我们不需要手动再次初始化按键&#xff0c;即可完成按键的读取。 二、代码实现 首先&#xff0c;我们一起来阅读hal_key.c中的代码&#xff1a; /* Includes -------------------------------------…

点云地面滤波--patchwork++

文章目录 1前言2 反射噪声去除RNR3区域垂直平面拟合 (R-VPF)4自适应地面似然估计(A-GLE)5时序地面恢复TGR总结 1前言 patchwork是在patchwork的基础上进行改进的&#xff0c;主要有2个贡献&#xff1a; 提出了自适应地面似然估计(adaptive ground likelihood estimation (A-G…

Java实训日记第一天——2023.6.6

这里写目录标题 一、关于数据库的增删改查总结&#xff1a;五步法1.增2.删3.改4.查 二、设计数据库的步骤第一步&#xff1a;收集信息第二步&#xff1a;标识对象第三步&#xff1a;标识每个实体的属性第四步&#xff1a;标识对象之间的关系 一、关于数据库的增删改查 总结&am…