【STL】优先级队列剖析及模拟实现

这篇具有很好参考价值的文章主要介绍了【STL】优先级队列剖析及模拟实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

作者阿润菜菜
📖专栏C++



什么是优先级队列,它与普通队列有什么区别和优势

优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的(默认大堆)。优先级队列的内部实现通常是用来维护元素的优先级,使得每次出队的元素都是当前队列中优先级最高的元素。

优先级队列与普通队列的区别和优势有以下几点:

  • 优先级队列可以根据元素的大小、时间、重要性等因素来定义优先级,使得出队顺序更加灵活和合理。
  • 优先级队列可以高效地找到最大或最小的元素,而不需要对整个队列进行排序。
  • 优先级队列可以应用于一些需要动态调整顺序的场景,如任务调度、事件处理、数据压缩等。

底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭
代器访问,并支持以下操作:

empty():检测容器是否为空

  • size():返回容器中有效元素个数
  • front():返回容器中第一个元素的引用
  • push_back():在容器尾部插入元素
  • top( ) 返回优先级队列中最大(最小元素),即堆顶元素
  • pop_back():删除容器尾部元素
  1. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。
  2. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。
  3. 优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。注意:默认情况下priority_queue是大堆

优先级队列的常用操作和方法,如入队、出队、获取最高优先级元素等

【STL】优先级队列剖析及模拟实现

优先级队列的常用操作和方法有以下几种:

  • 入队:将一个元素和它的优先级插入到优先级队列中,通常用enqueue或add方法表示。
    – 例如,pq.enqueue(‘a’, 1)或pq.add(‘a’, 1)表示将元素’a’和它的优先级1插入到优先级队列pq中。
  • 出队:将优先级队列中优先级最高(或最低)的元素移除并返回,通常用dequeue或pop方法表示。
    –例如,pq.dequeue()或pq.pop()表示将优先级队列pq中优先级最高的元素移除并返回。
  • 获取最高优先级元素:查看优先级队列中优先级最高(或最低)的元素,但不移除它,通常用front、peek或top方法表示。
    –例如,pq.front()、pq.peek()或pq.top()表示查看优先级队列pq中优先级最高的元素,但不移除它。
  • 判断是否为空:检查优先级队列是否为空,通常用isEmpty或empty方法表示。
    –例如,pq.isEmpty()或pq.empty()表示检查优先级队列pq是否为空。
  • 获取元素个数:返回优先级队列中元素的个数,通常用size方法表示。
    –例如,pq.size()表示返回优先级队列pq中元素的个数。
  • 转换为字符串:以字符串的形式展示优先级队列中的所有元素和它们的优先级,通常用toString方法表示。
    –例如,pq.toString()表示以字符串的形式展示优先级队列pq中的所有元素和它们的优先级。

priority_queue的模拟实现

优先级队列的内部实现原理,如何利用堆来维护元素的优先级

【STL】优先级队列剖析及模拟实现

  1. 优先级队列的内部实现原理是利用一种特殊的数据结构,叫做堆。堆是一种完全二叉树,它的每个节点都小于(或大于)它的所有后代,这样就可以保证根节点是最小(或最大)的元素。

  2. 优先级队列可以用数组来存储堆的结构,数组中第一个元素是根节点,然后按照层次顺序依次存储其他节点。数组中下标为k的元素的父节点的下标为k/2,其子节点的下标为2k和2k+1。

  3. 优先级队列的插入和删除操作都需要维护堆的有序性。插入操作是将元素追加到数组的尾部,然后执行上浮操作,即递归地将元素与其父节点比较并交换,直到找到合适的位置或者到达根节点。删除操作是将数组中第一个元素(即最小或最大元素)移除,并将数组中最后一个元素移到第一个位置,然后执行下沉操作,即递归地将元素与其子节点比较并交换,直到找到合适的位置或者到达叶子节点。

优先级队列的常用接口实现

#pragma once

#include <iostream>
using namespace std;

#include <vector>
// priority_queue--->堆
namespace HUE
{
	template<class T>
	struct less
	{
		bool operator()(const T& left, const T& right)
		{
			return left < right;
		}
	};

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

	template<class T, class Container = std::vector<T>, class Compare = less<T>>
	class priority_queue
	{
	public:
		// 创造空的优先级队列
		priority_queue() : c() {}

		template<class Iterator>
		priority_queue(Iterator first, Iterator last)
			: c(first, last)
		{
			// 将c中的元素调整成堆的结构
			int count = c.size();
			int root = ((count - 2) >> 1);
			for (; root >= 0; root--)
				AdjustDown(root);
		}

		void push(const T& data)
		{
			c.push_back(data);
			AdjustUP(c.size() - 1);
		}

		void pop()
		{
			if (empty())
				return;

			swap(c.front(), c.back());
			c.pop_back();
			AdjustDown(0);
		}

		size_t size()const
		{
			return c.size();
		}

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

		// 堆顶元素不允许修改,因为:堆顶元素修改可以会破坏堆的特性
		const T& top()const
		{
			return c.front();
		}
	private:
		// 向上调整
		void AdjustUP(int child)
		{
			int parent = ((child - 1) >> 1);
			while (child)
			{
				if (Compare()(c[parent], c[child]))
				{
					swap(c[child], c[parent]);
					child = parent;
					parent = ((child - 1) >> 1);
				}
				else
				{
					return;
				}
			}
		}

		// 向下调整
		void AdjustDown(int parent)
		{
			size_t child = parent * 2 + 1;
			while (child < c.size())
			{
				// 找以parent为根的较大的孩子
				if (child + 1 < c.size() && Compare()(c[child], c[child + 1]))
					child += 1;

				// 检测双亲是否满足情况
				if (Compare()(c[parent], c[child]))
				{
					swap(c[child], c[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
					return;
			}
		}
	private:
		Container c;
	};
}

void TestQueuePriority()
{
	HUE::priority_queue<int> q1;
	q1.push(5);
	q1.push(1);
	q1.push(4);
	q1.push(2);
	q1.push(3);
	q1.push(6);
	cout << q1.top() << endl;

	q1.pop();
	q1.pop();
	cout << q1.top() << endl;

	vector<int> v{ 5,1,4,2,3,6 };
	HUE::priority_queue<int, vector<int>, HUE::greater<int>> q2(v.begin(), v.end());
	cout << q2.top() << endl;

	q2.pop();
	q2.pop();
	cout << q2.top() << endl;
}
  1. 优先级队列是一个适配器,底层传入vector或者dequee都没有影响
  2. 大堆怎么变小堆?— 利用仿函数 — 怎么实现? 泛型编程,模板的力量— 实例化时传给什么类就是比较什么(传一个类,整个类都可以使用 ),就像是一个开关,你打开什么由你自己决定去控制

优先级队列的应用场景和示例,如任务调度、事件处理、数据压缩等

  • 任务调度:优先级队列可以用来实现一个任务调度系统,其中每个任务都有一个优先级,优先级高的任务先被执行。例如,操作系统中的进程调度,网络中的数据包传输,医院中的急诊病人处理等都可以使用优先级队列来实现。
  • 事件处理:优先级队列可以用来实现一个事件处理系统,其中每个事件都有一个发生时间,发生时间早的事件先被处理。例如,模拟器中的事件驱动模拟,游戏中的动画效果,日程管理软件中的提醒功能等都可以使用优先级队列来实现。
  • 数据压缩:优先级队列可以用来实现一种数据压缩算法,称为哈夫曼编码(Huffman Coding),其中每个字符都有一个出现频率,出现频率高的字符用较短的编码,出现频率低的字符用较长的编码。例如,文本文件,图片文件,音频文件等都可以使用哈夫曼编码来压缩。

优先级队列的优缺点和改进方向,如如何提高效率、节省空间、扩展功能等

优先级队列的优缺点和改进方向有以下几种:

  • 优点:优先级队列可以高效地实现一些需要不断地取出最大或最小元素的场景,例如任务调度,事件处理,数据压缩等。优先级队列的插入和删除操作的时间复杂度都是O(logn),比线性结构要快得多。
  • 缺点:优先级队列的空间复杂度是O(n),比线性结构要高一些。优先级队列的实现通常基于二叉堆,而二叉堆的结构可能会导致内存碎片和缓存不命中。优先级队列的排序规则可能不够灵活,例如不能同时考虑多个因素的优先级。
  • 改进方向:优先级队列的实现可以使用其他的数据结构,例如斐波那契堆,配对堆,二项堆等,这些数据结构可以提高某些操作的效率,例如合并两个优先级队列。优先级队列的排序规则可以使用自定义的比较器或者复合键来实现更多样化的需求。优先级队列的空间占用可以通过动态调整容量或者使用压缩技术来减少。

参考:Priority Queue
【STL】优先级队列剖析及模拟实现文章来源地址https://www.toymoban.com/news/detail-421245.html

到了这里,关于【STL】优先级队列剖析及模拟实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 优先级队列priority_queue模拟实现

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

    2024年02月02日
    浏览(27)
  • 【C++】优先级队列的基本概念以及其模拟实现

    🌏博客主页: 主页 🔖系列专栏: C++ ❤️感谢大家点赞👍收藏⭐评论✍️ 😍期待与大家一起进步! C++仿函数(function object)是一种可以像函数一样调用的对象。仿函数通常是一个类,它重载了函数调用运算符operator(),使得对象可以被调用。 仿函数就是基于函数模板生成

    2024年02月15日
    浏览(27)
  • 【c++】:“无敌的适配器来咯“栈和队列模拟实现以及优先级队列的模拟实现。

        文章目录 前言 一.栈和队列的模拟实现 二.优先级队列 总结   栈的介绍和使用: 1. stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。 2. stack是作为容器适配器被实现的,容器适配器即是对特定类封

    2024年02月01日
    浏览(26)
  • [C++历练之路]优先级队列||反向迭代器的模拟实现

    W...Y的主页 😊  代码仓库分享💕 🍔前言: 在C++的宇宙中,优先队列似乎是一座巨大的宝库,藏匿着算法的珍宝。而就在这片代码的天空下,我们不仅可以探索优先队列的神奇,还能够揭开反向迭代器的神秘面纱。让我们一同踏入这个编程的探险之旅,在这里,我们将用C

    2024年02月04日
    浏览(35)
  • Java【优先级队列】详细图解 / 模拟实现 + 【PriorityQueue】常用方法介绍

    📕各位读者好, 我是小陈, 这是我的个人主页 📗小陈还在持续努力学习编程, 努力通过博客输出所学知识 📘如果本篇对你有帮助, 烦请点赞关注支持一波, 感激不尽 📙 希望我的专栏能够帮助到你: JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管理系统

    2024年02月07日
    浏览(33)
  • 【C++初阶】模拟实现优先级队列priority_queue

    👦个人主页:@Weraphael ✍🏻作者简介:目前学习C++和算法 ✈️专栏:C++航路 🐋 希望大家多多支持,咱一起进步!😁 如果文章对你有帮助的话 欢迎 评论💬 点赞👍🏻 收藏 📂 加关注✨ 优先级队列顾名思义就是 按优先级出队列 priority_queue 是一个容器适配器,默认使用

    2024年02月10日
    浏览(29)
  • 【C++杂货铺】优先级队列的使用指南与模拟实现

    优先级队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的。 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先级队列中位于顶部的元素)。 优先级队列被实现为容器适配器,容器适配器即将特定容器

    2024年02月09日
    浏览(34)
  • C++基础(三)——STL优先级队列

    模板输入 1、元素类型 2、容器类型 3、函数对象类型 priority_queueint name; priority_queue默认为大顶堆 故定义也可以写作: priority_queueint, vectorint, lessint ay; 如果需要构建一个小顶堆,可以改变定义方式为: priority_queueint, vectorint, greaterint ay; 使用std::greater模板无需自定义比较函数。

    2024年02月09日
    浏览(43)
  • C++ STL学习之【优先级队列】

    ✨个人主页: 北 海 🎉所属专栏: C++修行之路 🎃操作环境: Visual Studio 2019 版本 16.11.17 优先级队列 priority_queue 是容器适配器中的一种,常用来进行对数据进行优先级处理,比如优先级高的值在前面,这其实就是初阶数据结构中的 堆 ,它俩本质上是一样东西,底层都是以数

    2024年02月05日
    浏览(35)
  • 【STL】优先级队列&反向迭代器详解

    目录 一,栈_刷题必备 二,stack实现 1.什么是容器适配器 2.STL标准库中stack和queue的底层结构  了解补充:容器——deque  1. deque的缺陷 2. 为什么选择deque作为stack和queue的底层默认容器 三,queue实现 1. 普通queue  2,优先级队列(有难度) 1. 功能 2. 模拟实现 1). 利用迭代器_构造

    2024年02月13日
    浏览(32)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包