priority_queue 优先级队列(堆) 的模拟实现

news2025/6/8 20:59:22

目录

一、优先级队列的模板参数列表

二、优先级队列的构造函数(建堆 nlogn)

AdjustDown() 向下调整:

建堆的时间复杂度:

三、pop()接口 (堆顶元素的删除: logn)

四、push()接口 (logn)

AdjustUp() 向下调整:

五、其他函数

六、源码及测试:


priority_queue 的本质就是堆,以下来介绍优先级队列的模拟实现

一、优先级队列的模板参数列表

 定义优先级队列类,模板参数分别为存入元素的类型T,

                                存放元素的底层结构默认使用std命名空间中的vector<T>、

                                以及比较方式less<T>,也给出了less类、以及Greater类

template<class T>
	class less
	{
	public:
		bool operator()(const T& left, const T& right)const
		{
			return left < right;
		}
	};
	template<class T>
	class Greater
	{
	public:
		bool operator()(const T& left, const T& right)const
		{
			return left > right;
		}
	};
	template <class T, class Contioner = std::vector<T>, class Compare = less<T>>
    class priority_queue
    {
    
    };

二、优先级队列的构造函数(建堆 时间复杂度为nlogn

这一步最重要的就是建堆,具体思路就是从优先级队列(堆)的第一个非叶子结点开始来进行向下调整,直到将顶点元素也完成向下调整。

首先利用类中对数组(默认Container使用vector<T>)_con中的vector的区间构造函数来对_con进行初始化。

然后对从第一个非叶子结点的位置进行向下调整直到将堆顶元素也进行向下调整为止。

    class priority_queue
	{
	public:
		priority_queue()
		{}

		template<class Iterator>
		priority_queue(Iterator first, Iterator last)
			: _con(first, last) // 1、使用vector的区间构造函数来初始化_con
		{
			// 2、建堆:从完全二叉树的最后一个非叶子结点来进行向下调整
			for (int i = (size() - 2) / 2; i >= 0; i--)
			{
				AdjustDown(i);
			}
		}
     private:
         Container _con;
    };

AdjustDown() 向下调整:

        在parent的右孩子存在的条件下,选择俩个孩子中较大的那个来进行与parent的比较,如果parent位置元素小于child位置元素,就进行交换,parent和child都不断向下更新重复判断,直到parent大于child或者child超出访问范围。

建堆的时间复杂度:

        为向下调整的时间复杂度logn * 遍历元素的n 即为 nlogn

        private:
		void AdjustDown(int parent)
		{
			size_t sz = size();
			int child = 2 * parent - 1;
			Compare com;
			while (child < sz)
			{
				// 如果左孩子存在  且  左孩子小于右孩子  就将child进行更新
				if (child + 1 < sz && com(_con[child], _con[child + 1]))
					child += 1;
				if (com(_con[parent], _con[child]))
				{
					std::swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 - 1;
				}
				else
					return;
			}
		}

三、pop()接口 (堆顶元素的删除: logn)

即为固定的3步走:看下方代码即可。

        void pop()
		{
			// 1、将堆顶元素与最后一个元素进行位置交换
			std::swap(_con[0], _con[size() - 1]);

			// 2、将换到最后一个位置的堆顶元素进行尾删
			_con.pop_back();

			// 3、将新的堆顶元素进行向下调整
			AdjustDown(0);
		}

四、push()接口 (logn)

将待插入元素尾插进_con,然后对该元素进行向上调整即可

        void push(T val)
		{
			// 1、将代插入的元素进行尾部插入
			_con.push_back(val);

			// 2、将该元素进行向上调整
			AdjustUp();
		}

AdjustUp() 向下调整:

        void AdjustDown(size_t parent)
		{
			size_t sz = size();
			size_t child = 2 * parent + 1;
			Compare com;
			while (child < sz)
			{
				// 如果左孩子存在  且  左孩子小于右孩子  就将child进行更新
				if (child + 1 < sz && com(_con[child], _con[child + 1]))
					child += 1;
				if (com(_con[parent], _con[child]))
				{
					std::swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
					return;
			}
		}

五、其他函数

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

		const T& top()const
		{
			return _con[0];
		}

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

六、源码及测试:

#include<iostream>
#include<vector>
using namespace std;
namespace wei
{
	template<class T>
	class less
	{
	public:
		bool operator()(const T& left, const T& right)const
		{
			return left < right;
		}
	};
	template<class T>
	class Greater
	{
	public:
		bool operator()(const T& left, const T& right)const
		{
			return left > right;
		}
	};
	template <class T, class Contioner = std::vector<T>, class Compare = less<T>>
	class priority_queue
	{
	public:
		priority_queue()
		{}

		template<class Iterator>
		priority_queue(Iterator first, Iterator last)
			: _con(first, last) // 1、使用vector的区间构造函数来初始化_con
		{
			// 2、建堆:从完全二叉树的最后一个非叶子结点来进行向下调整
			for (int i = (size() - 2) / 2; i >= 0; i--)
			{
				AdjustDown(i);
			}
		}

		void push(T val)
		{
			// 1、将代插入的元素进行尾部插入
			_con.push_back(val);

			// 2、将该元素进行向上调整
			AdjustUp();
		}

		void pop()
		{
			if (empty())
				return;
			// 1、将堆顶元素与最后一个元素进行位置交换
			std::swap(_con[0], _con[size() - 1]);

			// 2、将换到最后一个位置的堆顶元素进行尾删
			_con.pop_back();

			// 3、将新的堆顶元素进行向下调整
			AdjustDown(0);
		}

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

		const T& top()const
		{
			return _con[0];
		}

		bool empty()const
		{
			return _con.empty();
		}
	private:
		void AdjustDown(size_t parent)
		{
			size_t sz = size();
			size_t child = 2 * parent + 1;
			Compare com;
			while (child < sz)
			{
				// 如果左孩子存在  且  左孩子小于右孩子  就将child进行更新
				if (child + 1 < sz && com(_con[child], _con[child + 1]))
					child += 1;
				if (com(_con[parent], _con[child]))
				{
					std::swap(_con[parent], _con[child]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
					return;
			}
		}
		void AdjustUp()
		{
			size_t child = size() - 1;
			Compare com;
			size_t parent = (child - 1) / 2;
			while (child)
			{
				if (com(_con[parent], _con[child]))
				{
					std::swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
					return;
			}
		}
	private:
		Contioner _con;
	};
}

void TestMyPriority_queue1()
{
	int array[] = { 1,2,3,4,5,6,7,8,9 };
	wei::priority_queue<int> q(array, array+sizeof(array)/sizeof(array[0]));
	cout << q.size() << endl;
	cout << q.top() << endl;
}

void TestMyPriority_queue2()
{
	wei::priority_queue<int> q;
	q.push(1);
	q.push(2);
	q.push(3);
	q.push(4);
	q.push(5);
	q.push(6);
	cout << q.size() << endl;
	cout << q.top() << endl;
	q.pop();
	q.pop();
	cout << q.size() << endl;
	cout << q.top() << endl;
}

void TestMyPriority_queue3()
{
	int array[] = { 1,2,3,4,5,6,7,8,9 };
	wei::priority_queue<int, vector<int>, wei::Greater<int>> q(array, array + sizeof(array) / sizeof(array[0]));
	cout << q.size() << endl;
	cout << q.top() << endl;
}

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

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

相关文章

算法第九期——DFS(深度优先搜索)对树的应用

树 树是一种特殊的图 。 特点&#xff1a; 若树有n个点,则有n-1条边。树有连通性但没有回路。从一个点出发可以到达任意一个&#xff0c;而且路径是唯一的。树的重心u&#xff08;最平衡的点&#xff09;: 以树上任意一个结点为根计算它的子树的结点数&#xff0c;如果结点…

1578_AURIX_TC275_MTU中的ECC检测、错误追踪以及运行模式

全部学习汇总&#xff1a; GreyZhang/g_TC275: happy hacking for TC275! (github.com) EOV其实是体现了一个错误递增的概念&#xff0c;而且这个是积累到了一定的度。至于具体的规则&#xff0c;其实后面还有更加详细的信息。关于ECC错误纠正使能&#xff0c;相应的处理可能跟…

产品更新!数维图编辑器超10项功能升级

新的一年我们加紧了更新迭代的速度&#xff0c;覆盖数维图三大可视化编辑器产品&#xff0c;超10项功能升级优化。我们将继续保持每天更新的产品升级节奏&#xff0c;满足不同行业用户的更多需求&#xff0c;为用户带来极致的产品使用体验。以下是主要的亮点功能更新汇总&#…

用R语言理解连续性和导数

文章目录微分1 连续性2 求导微分 1 连续性 众所周知微分的几何意义是斜率&#xff0c;然而斜率最初的定义只涉及直线&#xff0c;指的是ykxbykxbykxb中的kkk&#xff0c;而对任意曲线yf(x)yf(x)yf(x)而言&#xff0c;若想谈其斜率&#xff0c;就必须先做出其切线&#xff0c;…

#A. 毛毛虫树

Description给你一棵树希望你找出一条链来&#xff0c;这条链上的点&#xff0c;及这些点直接相连的点&#xff0c;加起来点数尽可能的多FormatInput第一行两个整数N&#xff0c;M&#xff0c;分别表示树中结点个数和树的边数。接下来M行&#xff0c;每行两个整数a, b表示点a和…

lombok快速入门

lombok快速入门 1.安装idea lombok插件 2.加入 maven 依赖 lombok常用注解 1. Getter/Setter 自动产生 getter/setter 2. ToString 自动重写 toString() 方法&#xff0c;会打印出所有变量 3. EqualsAndHashCode 自动生成 equals(Object other) 和 hashcode() 方法&#x…

MATLAB实验四

1.求方程2x5−3x371x2−9x1302x^5-3x^371x^2-9x1302x5−3x371x2−9x130 的全部根 >> p[2 0 -3 71 -9 13]; >> pkg load symbolic >> poly2sym(p) Symbolic pkg v3.0.0: Python communication link active, SymPy v1.10.1. ans (sym)5 3 22*x -…

FPGA图像处理HLS实现sobel边沿检测,提供HLS工程和vivado工程源码

目录一、sobel边沿检测原理二、HLS方案实现sobel边沿检测三、HLS在线仿真并导出IP四、Kintex7开发板vivado工程验证五、zynq7100开发板vivado工程验证六、板级调试验证七、福利&#xff1a;工程源码获取一、sobel边沿检测原理 所谓边缘是指其周围像素灰度急剧变化的那些象素的…

CS架构 企业ERP系统源码 Winform财务设备生产采购进销存源码

淘源码&#xff1a;国内知名的源码免费下载平台 推荐环境&#xff1a;vs2019 sql server 2008 r2以上 源码简介 本系统属于中小型企业ERP管理系统&#xff0c;可以对中小型生产企业或商业企业进行有效管理。 系统包含进销存、财务、生产、委外、财务、设备管理、权限管理等模…

【可解释性机器学习】基于ELI5使用解读LIME算法以及实战案例

LIME算法解读与实战案例LIME论文简介LIME算法原理LIME算法要点LIME的注意事项LIME的代码实现对Pytorch搭建的模型进行解释使用LIME解释Pytorch构建的模型参考资料LIME论文简介 LIME的全称为Local Interpretable Model-agnostic Explanations. 尽管被广泛采用&#xff0c;机器…

模板进阶篇

一、非类型模板参数 模板参数分类类型形参与非类型形参。 类型形参&#xff1a;出现在模板参数列表中&#xff0c;跟在class或者typename之类的参数类型名称。如图&#xff1a; 非类型形参&#xff1a;就是用一个常量作为类(函数)模板的一个参数&#xff0c;在类(函数)模板中可…

Mybatis 原理之启动阶段

文章目录1.MyBatis 核心流程2.启动准备阶段流程3.创建 SQlSessionFactory4.创建XMLConfigBuilder5.创建 XPathParser6.解析并设置 configuration 中的属性7.解析Mappers标签1.MyBatis 核心流程 Mybatis的核心流程氛围两个阶段&#xff0c;启动准备阶段和执行SQL阶段。 加载配…

Day858.高性能网络应用框架Netty -Java 并发编程实战

高性能网络应用框架Netty Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于高性能网络应用框架Netty的内容。 Netty 是一个高性能网络应用框架&#xff0c;应用非常普遍&#xff0c;目前在 Java 领域里&#xff0c;Netty 基本上成为网络程序的标配了。 Netty 框架功…

win10录屏软件哪款比较好用?一款不限时长的录屏软件

现在大部分人的电脑都是win10系统的电脑&#xff0c;也有许多小伙伴会经常会问&#xff1a;“win10电脑怎么录屏&#xff1f;”录制电脑屏幕&#xff0c;需要使用到录屏软件&#xff0c;那win10录屏软件哪款比较好用&#xff1f;小编今天给大家分享一款试用版即可不限录制时长的…

【区间合并】洛谷 P1496 火烧赤壁

P1496 火烧赤壁 文章目录题目背景题目描述输入格式&#xff1a;输出格式&#xff1a;数据范围输入样例输出样例方法&#xff1a;区间合并解题思路代码复杂度分析&#xff1a;题目背景 曹操平定北方以后&#xff0c;公元 208 年&#xff0c;率领大军南下&#xff0c;进攻刘表。…

部分时变离散系统中的稳定性判据

部分时变离散系统中的稳定性判据 1.Lyapunov稳定性理论 下面先给出Lyapunov稳定性的一些基本理论&#xff08;网上资源较多这里不再过多赘述&#xff09;&#xff1a; 2.一类时变离散系统的稳定性 定理 ​ 对于离散时变系统x(k1)A(k)x(k)x(k1)A(k)x(k)x(k1)A(k)x(k)&#x…

Java EE|多线程代码实例之单例模式与阻塞队列

文章目录前言设计模式介绍&#x1f534;单例模式什么是单例模式单例模式实现方式饿汉模式懒汉模式基于上述单例模式实现线程安全问题讨论重点回顾&#x1f534;阻塞队列阻塞队列是什么标准库中的阻塞队列典型应用场景&#xff1a;生产者消费者模型利用系统提供的BlockingQueue实…

osg fbo(三),将颜色缓冲区图片通过shader变绿

这个其实很简单&#xff0c; 一&#xff0c;写顶点着色器和片元着色器 static const char * vertexShader { “void main(void)\n” “{\n” " gl_Position ftransform();\n" “}\n” }; static const char *psShader { “uniform float alpha;” “void main(vo…

12、ThingsBoard-如何配置发送邮件

1、概述 ThingsBoard提供了系统层设置邮件配置和租户层通过设置邮件规则节点,对规则引擎产生的告警进行分发这两种邮件配置,其中系统层设置邮件配置主要是针对用于向用户分发激活和密码重置电子邮件;租户层通过设置邮件规则节点是针对告警通知的;一定要区别开这两个邮件配…

SpringBoot整合SpringSecurity实现进行认证和授权。

目录 2.在子工程通过easyCode创建项目相关包和文件 3.子项目新建Controllter层&#xff0c;并建立BlogLoginController.java 4.在servic 层定义login 方法&#xff0c;并new UsernamePasswordAuthenticationToken对象&#xff0c;传入对应用户名&#xff0c;密码 5.自定义实…