【C++】priority_queue模拟实现过程中值得注意的点

这篇具有很好参考价值的文章主要介绍了【C++】priority_queue模拟实现过程中值得注意的点。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【C++】priority_queue模拟实现过程中值得注意的点,C++,c++,开发语言

👀樊梓慕:个人主页

 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C++》《Linux》《算法》

🌝每一个不曾起舞的日子,都是对生命的辜负


前言

本篇文章旨在记录博主在模拟实现priority_queue适配器中遇到的一些问题,希望与大家共勉。


欢迎大家📂收藏📂以便未来做题时可以快速找到思路,巧妙的方法可以事半功倍。

=========================================================================文章来源地址https://www.toymoban.com/news/detail-818451.html

GITEE相关代码:🌟fanfei_c的仓库🌟

=========================================================================


1.priority_queue的介绍

  • priority_queue顾名思义:『 优先级队列』;
  • 人话:

priority_queue就是基于vector容器的堆,所以未来涉及到『 堆的应用』都可以使用priority_queue适配器。

默认为大堆。

【C++】priority_queue模拟实现过程中值得注意的点,C++,c++,开发语言

同样通过模板参数的方式来决定底层容器和构建小堆。

比如:

  • 使用『 vector』作为底层容器,内部构造『 大堆』结构。
priority_queue<int, vector<int>, less<int>> q1;
  • 使用『 vector』作为底层容器,内部构造『 小堆』结构。
priority_queue<int, vector<int>, greater<int>> q2;
  • 不指定底层容器和内部需要构造的堆结构,采用默认即vector、大堆。
priority_queue<int> q;

比较奇怪的是:

构建大堆要传less,构建小堆要传greater,容易记混。

  • 『 大堆』less就是逐渐变小;
  • 『 小堆』greater就是逐渐变大。

2.堆的回顾

2.1向上调整算法

向上调整算法的前提是『 祖先是堆』。

以小堆为例:

1.给定向上调整的起点(孩子节点下标),根据起点下标计算双亲节点下标。

孩子节点与双亲结点间的下标关系:

  • child=parent*2+1 || child=parent*2+2;
  • parent=(child-1)/2;

2.比较孩子节点与双亲节点数值大小,若孩子节点小于于双亲节点,则交换两者,并将孩子节点的下标更新为之前的双亲节点下标,根据最新的孩子节点下标重新计算双亲节点下标,重复这一过程直到孩子节点为根节点。

【C++】priority_queue模拟实现过程中值得注意的点,C++,c++,开发语言

//堆的向上调整(小堆)
void AdjustUp(vector<int>& v, int child)
{
	int parent = (child - 1) / 2; //通过child计算parent的下标
	while (child > 0)//调整到根结点的位置截止
	{
		if (v[child] < v[parent])//孩子结点的值小于父结点的值
		{
			//将父结点与孩子结点交换
			swap(v[child], v[parent]);
			//继续向上进行调整
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

2.2向下调整算法

向下调整算法的前提是『 左右子树是堆』。

以小堆为例:

1.给定向下调整的起点(双亲节点下标)和节点总数,根据起点下标计算孩子节点下标。

注意:向下调整时,若有两个孩子节点,则需要确保调整的是较小的孩子节点。

2.比较孩子节点与双亲节点数值大小,若孩子节点小于双亲节点,则交换两者,并将双亲节点的下标更新为之前的孩子节点下标,根据最新的双亲节点下标重新计算孩子节点下标,重复这一过程直到孩子节点超出节点总数。

【C++】priority_queue模拟实现过程中值得注意的点,C++,c++,开发语言

//堆的向下调整(小堆)
void AdjustDown(vector<int>& v, int n, int parent)
{
	//child记录左右孩子中值较大的孩子的下标
	int child = 2 * parent + 1;//先默认其左孩子的值较小
	while (child < n)
	{
		if (child + 1 < n && v[child+1] < v[child])//右孩子存在并且右孩子比左孩子还小
		{
			child = child + 1;//较小的孩子改为右孩子
		}
		if (v[child] < v[parent])//左右孩子中较小孩子的值比父结点还小
		{
			//将父结点与较小的子结点交换
			swap(v[child], v[parent]);
			//继续向下进行调整
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}

3.构建大小堆的模板参数问题『仿函数 』 

这里同样涉及到模板参数的传递问题。

在学习堆时,我们知道可以通过改变比较方式从而实现建大堆或者建小堆:

【C++】priority_queue模拟实现过程中值得注意的点,C++,c++,开发语言

但我们不能每次都手动的去改变这个符号从而满足用户需求。

所以这里我们同样可以利用『 仿函数』来解决这一问题。

仿函数是一个类或结构体,它重载了operator()运算符,使其可以像函数一样被调用。

仿函数的实例可以像函数指针一样传递给STL算法或容器的操作,从而实现自定义行为。

如同我们今天的例子,_com是less类的实例对象,less类重载了操作符(),使其类似于函数调用,内部实现比较大小的功能返回布尔值,_com()就是仿函数,该仿函数模拟了函数行为,使if的判断条件为真或假,从而达到我们>、<的目的。 

【C++】priority_queue模拟实现过程中值得注意的点,C++,c++,开发语言 

  • 函数参数传参是在『 使用时传参』,传递的是『 对象』;
  • 模板参数传参是在『 编译时传参』,传递的是『 类型』。

4.模拟实现源码

#pragma once

namespace F
{
    //比较方式:减小堆
	template<class T>
	class less
	{
	public:
		bool operator()(const T& x, const T& y)
		{
			return x < y;
		}
	};
    //比较方式:建大堆
	template<class T>
	class greater
	{
	public:
		bool operator()(const T& x, const T& y)
		{
			return x > y;
		}
	};
	template<class T, class Container = std::vector<T>, class Compare = less<T>>
	class priority_queue
	{
	public:
        //向上调整
		void adjust_up(int child)
		{
			int parent = (child - 1) / 2;
			while (child > 0)
			{
                //通过模板参数Compare确定是否需要交换结点位置
				if (_com(_con[child],_con[parent]))
				{
					swap(_con[child], _con[parent]);
					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() && _com(_con[child+1],_con[child]))
				{
					++child;
				}

				if (_com(_con[child], _con[parent]))
				{
					swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}

		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);
		}

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

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

		bool empty()
		{
			return _con.empty();
		}
	private:
		Container _con;//底层容器
		Compare _com;//比较方式
	};
}

=========================================================================

如果你对该系列文章有兴趣的话,欢迎持续关注博主动态,博主会持续输出优质内容

🍎博主很需要大家的支持,你的支持是我创作的不竭动力🍎

🌟~ 点赞收藏+关注 ~🌟

=========================================================================

到了这里,关于【C++】priority_queue模拟实现过程中值得注意的点的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++初阶】仿函数和priority_queue的模拟实现(附源码)

    仿函数,顾名思义就是 模仿函数,它其实是一个类,类里面重载了运算符() ,在调用这个重载的运算符时,让我们感觉是调用函数一样,可以说相当于C语言里的函数指针一样,但是函数指针的可读性不好,不如仿函数。 1.仿函数即使定义相同,也可能有不同的类型; 2.仿

    2024年02月16日
    浏览(32)
  • C++:stack、queue、priority_queue增删查改模拟实现、deque底层原理

    我们先来看看 stack的相关接口有哪些: 从栈的接口,我们可以知道栈的接口是一种特殊的vector,所以我们完全可以使用vector来模拟实现stack。 因此我们可以将底层容器定义成模板,然后将容器类变量作为成员变量进行封装。在实现satck的各种接口时,通过成员变量来调用底层

    2024年02月03日
    浏览(42)
  • 【C++】——栈和队列(stack、queue)及优先队列(priority_queue)的介绍和模拟实现

    今天我们来学习C++stl六大组件的其中一种,容器适配器,stack、queue及priority_queue都是容器适配器。我们循序渐进,接下来让我们先认识一下什么是容器适配器。 适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该

    2024年02月08日
    浏览(46)
  • 【C++】STL优先级队列(priority_queue)功能介绍以及模拟实现

    点进来的小伙伴不知道学过数据结构里的堆没有,如果学过的话,那就好说了,优先级队列就是堆,如果没学过,没关系,可以参考一下我之前写的一篇关于堆的博客,可以点进去看看:【数据结构】堆(包含堆排序和TOPK问题) 那么了解过堆了的话,我就不讲那么细致了,

    2024年02月16日
    浏览(45)
  • 【C++】STL中的容器适配器 stack queue 和 priority_queue 的模拟实现

    适配器是一种设计模式 (设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户希望的另外一个接口。 例如我们常见的充电器就是一种适配器,它将我们常用的220V交流电压转化为4,5V (或者其他更高的电

    2023年04月26日
    浏览(59)
  • 容器适配器---deque和STL ---stack queue priority_queue的模拟实现 C++

    目录 一、容器适配器 deque原理 deque的缺陷 deque的优势 二、stack的模拟实现  三、queue的模拟实现 四、优先级队列的模拟实现 适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结),该种模式是将一个类的接口转换成客户

    2024年02月02日
    浏览(52)
  • 《priority_queue的模拟实现》

    本文主要介绍 所谓的仿函数(functor),是通过重载 () 运算符模拟函数形为的类。 因此,这里需要明确两点: 仿函数不是函数,它是个类; 仿函数重载了()运算符,使得它的对你可以像函数那样子调用(代码的形式好像是在调用函数)。(C语言中就是函数指针) 为了适应更多的

    2024年02月07日
    浏览(35)
  • 优先级队列priority_queue模拟实现

    🌟🌟hello,各位读者大大们你们好呀🌟🌟 🚀🚀系列专栏:【C++的学习】 📝📝本篇内容:C++容器优先级队列priority_queue模拟实现 ⬆⬆⬆⬆上一篇:string模拟实现 💖💖作者简介:轩情吖,请多多指教( •̀֊•́ ) ̖́- ①优先级队列是一种容器适配器,它的第一个元素总是

    2024年02月02日
    浏览(38)
  • 【STL】priority_queue的使用及模拟实现

    目录 前言 priority_queue的使用 功能解析 基本接口 写点题目 模拟实现 结构解析 插入删除 调整函数结合仿函数 仿函数介绍 结合使用 其他功能 接口补齐 迭代器区间构造 🍾打开 queue 头文件后,我们发现除了我们之前介绍过的普通队列以外,还有一个 priority_queue 。 🍾其又名为

    2024年02月08日
    浏览(39)
  • 【STL详解 —— priority_queue的使用与模拟实现】

    std::priority_queue 是 C++ 标准库中的容器适配器,它提供了一种基于堆的优先级队列实现。优先级队列是一种特殊的队列,其中的元素按照一定的优先级顺序排列,而不是按照它们被插入的顺序。 在 std::priority_queue 中,插入元素时会根据元素的值自动进行排序,最大(或最小)

    2024年04月17日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包