C++初阶 priority_queue(优先级队列)的使用和模拟实现

news2024/11/26 14:55:23

作者:@小萌新
专栏:@C++初阶
作者简介:大二学生 希望能和大家一起进步!
本篇博客简介:介绍优先级队列的使用和模拟实现

优先级队列的使用和模拟实现

  • priority_queue的使用
    • priority_queue的介绍
    • priority_queue的定义
    • priority_queue的使用
    • priority_queue的题目
  • priority_queue的模拟实现
    • 堆的向上调整
    • 堆的向下调整
    • 仿函数的实现
    • priority_queue模拟实现
  • 总结

priority_queue的使用

priority_queue的介绍

优先级队列(priority queue)
是0个或多个元素的集合,每个元素都有一个优先权,对优先级队列执行的操作有(1)查找(2)插入一个新元素(3)删除一般情况下,查找操作用来搜索优先权最大的元素,删除操作用来删除该元素。
对于优先权相同的元素,可按先进先出次序处理或按任意优先权进行。

这里还是用简单的语言来描述下

我们可以将优先级队列想象成一个堆(默认是大堆)

priority_queue的定义

它的定义包括下面的三个参数

priority_queue<int, vector<int>,less<int> > q1;

我们通过观察可以发现 这里的三个参数代表的分别是

存储的数据类型 存储的容器类型 比较的方式

其中存储容器的类型和比较方式都是可以省略的
(默认是 vector 和 less)

所以说可以衍生出下面的两种定义方式

	priority_queue<int, vector<int>> q2;
	priority_queue<int> q3;

实际上来说它们定义的优先级队列是相同的

tips : 这里的优先级队列设计的有点奇怪

less对应的是大堆 而greater则对应的是小堆

priority_queue的使用

接口函数如下

在这里插入图片描述
使用代码如下

void test_priority_queue()
{
	priority_queue<int, vector<int>, less<int> > q1;
	q1.push(1);
	q1.push(4);
	q1.push(9);
	q1.push(3);
	q1.push(7);

	while (!q1.empty())
	{
		cout << q1.top() << endl;
		q1.pop();
	}

}

这段代码的意思呢 就是我们随机插入几个数字

然后一个个打印出来 看看打印出来的顺序是什么?

显示结果如下

在这里插入图片描述
我们可以发现 它们在优先级队列中实际上就是按照从大到小的顺序

那么如果我们想到将它变成从小到大呢?

是不是改变下比较的仿函数就可以了

在这里插入图片描述
我们可以发现 变成greater之后就会是从小到大排序了

priority_queue的题目

在这里插入图片描述
就像这个问题 我们就可以使用我们的优先级队列来解决(堆)

因为大堆的顶部一定是最大的数字 所以说我们只需要删除掉前面top(k -1)个元素 之后我们就能得到我们第k大的数了

代码表示如下

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) 
    {
        // 我们使用优先级队列来做
        // 因为要求第k大的数字  所以说我们只要建立一个大堆
        // 然后pop掉前面k-1个数字 最后的一个数字就是我们要求的了
        priority_queue<int> q1;
        for (auto x : nums)
        {
            q1.push(x);
        }

        // 之后删掉前面k-1个数 就是第k大个数在最前面了
        while(k-1)
        {
            q1.pop();
            k--;
        }

        return q1.top();

        
    }
};

运行结果如下

在这里插入图片描述

priority_queue的模拟实现

我们前面已经说过了 priority_queue的底层其实就是堆

所以说要我们实现一个优先级队列和实现一个堆 其实是差不多的

注意! 博主下面的实现全部以大堆为例

堆的向上调整

在这里插入图片描述
主要用于我们建堆的时候

我们在堆的末尾插入一个元素

由于我们的堆是大堆的缘故 所以说父节点 一定是大于子节点的

这个时候我们就需要判断 我们的父节点是否确实大于我们的子节点

如果大于 我们就交换它们的位置 之后重复这个过程

void adjust_up(vector<int>& v ,int child)
{
	// 首先找出孩子的父节点
	int father = (child - 1) / 2;
	// 当子节点不为根节点时就一直判断
	while ( child > 0 )
	{
		if (v[child] > v[father])
		{
			swap(v[child], v[father]);
			child = father;
			father = (child - 1) / 2;
		}
		else
		{
			// 符合规则 直接跳出循环
			break;
		}
	}
}

堆的向下调整

向下调整通常用于删除数据的时候

同样的 我们如果直接删除大堆顶部的数据有点不太好操作

这个时候我们就可以将大堆顶部和底部的数据交换 之后删除底部的数据

这个时候我们只需要让顶部的元素 向下进行调整就好了

代码表示如下

void adjust_down(vector<int>& v, int father)
{
	int child = 2 * father + 1;//左孩子
	// 开始循环 直到父亲没有孩子 或者符合小堆结构位置
	while (child < v.size())
	{
		// 首先判断右孩子是否存在并且右孩子是否大于左孩子
		// 因为要是比较大的那个做父亲
		if (child + 1 < v.size() && v[child+1] > v[child])
		{
			child++;
		}
		// 之后就判断 孩子是否大于父亲 如果大于就交换并且继续比较 如果不大于就结束
		if (v[child] > v[father])
		{
			swap(v[child], v[father]);
			father = child;
			child = 2 * father + 1;
		}
		else
		{
			break;
		}

	}

}

仿函数的实现

两个很简单的仿函数 operator()重载

这两个函数比较特殊 我们先看代码

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

我们可以看到 它们实际上就是重载了一个括号运算符来判断大小而已

priority_queue模拟实现

namespace shy //防止命名冲突
{
	//比较方式(使内部结构为大堆)
	template<class T>
	struct less
	{
		bool operator()(const T& x, const T& y)
		{
			return x < y;
		}
	};
	//比较方式(使内部结构为小堆)
	template<class T>
	struct greater
	{
		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 AdjustUp(int child)
		{
			int parent = (child - 1) / 2; //通过child计算parent的下标
			while (child > 0)//调整到根结点的位置截止
			{
				if (_comp(_con[parent], _con[child]))//通过所给比较方式确定是否需要交换结点位置
				{
					//将父结点与孩子结点交换
					swap(_con[child], _con[parent]);
					//继续向上进行调整
					child = parent;
					parent = (child - 1) / 2;
				}
				else//已成堆
				{
					break;
				}
			}
		}
		//插入元素到队尾(并排序)
		void push(const T& x)
		{
			_con.push_back(x);
			AdjustUp(_con.size() - 1); //将最后一个元素进行一次向上调整
		}
		//堆的向下调整
		void AdjustDown(int n, int parent)
		{
			int child = 2 * parent + 1;
			while (child < n)
			{
				if (child + 1 < n&&_comp(_con[child], _con[child + 1]))
				{
					child++;
				}
				if (_comp(_con[parent], _con[child]))//通过所给比较方式确定是否需要交换结点位置
				{
					//将父结点与孩子结点交换
					swap(_con[child], _con[parent]);
					//继续向下进行调整
					parent = child;
					child = 2 * parent + 1;
				}
				else//已成堆
				{
					break;
				}
			}
		}
		//弹出队头元素(堆顶元素)
		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			AdjustDown(_con.size(), 0); //将第0个元素进行一次向下调整
		}
		//访问队头元素(堆顶元素)
		T& top()
		{
			return _con[0];
		}
		const T& top() const
		{
			return _con[0];
		}
		//获取队列中有效元素个数
		size_t size() const
		{
			return _con.size();
		}
		//判断队列是否为空
		bool empty() const
		{
			return _con.empty();
		}
	private:
		Container _con; //底层容器
		Compare _comp; //比较方式
	};
}

总结

在这里插入图片描述
优先级队列的模拟实现主要是运用到了堆的知识 对于目前的同学们来说还是比较简单的

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

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

相关文章

Solid.js前端新秀框架 力压 web3.js 框架

SolidJS 是什么&#xff1f;SolidJS是一个声明式、高效且灵活用于构建用户界面的 JavaScript 库。 Solid 号称拥有 JSX 语法&#xff0c;类似于 React hook 的语法&#xff0c;你可以用现代化的开发方式&#xff0c;获得性能最快的代码。 框架本身只有7 KB大小&#xff0c;无需…

【在SpringBoot项目中删除相册数据--Controller层】

在AlbumController中添加处理请求的方法&#xff1a; 请求路径&#xff1a;/album/delete请求方式&#xff1a;POST请求参数&#xff1a;Long id响应结果&#xff1a;JsonResult >>> state:20000 具体代码为&#xff1a; // http://localhost:9080/album/delete ApiO…

常用Assignment写作句型怎么积累?

Assignment是留学生在国外留学期间常见的写作内容。很多留学生在最初接触Assignment时往往会感到无从下手&#xff0c;更不知道该怎么去表达自己想要表达的内容。其实&#xff0c;Assignment写作并没有想象中那么难&#xff0c;在Assignment写作中有很多句型是经常用到的&#…

Windows win10 win11 多屏幻灯片放映壁纸 多屏设置不同的壁纸 多屏不同幻灯片壁纸

背景&#xff1a;windows 可以右键为不同的显示器设置不同的壁纸&#xff08;需要先关闭虚拟桌面&#xff09;。但是 slideshow 的不支持多个屏幕。 目前看这个问题是没有官方的方案的&#xff0c;理论上有一个收费软件可以解决&#xff0c;或者用*版&#xff0c;但是不想给钱…

React Fiber树的构建和替换过程

文章の目录前言mount 过程update 过程写在最后前言 React Fiber树的创建和替换过程运用了双缓存技术&#xff0c;即先在内存中创建 fiber 树&#xff0c;待 fiber 树创建完成以后&#xff0c;直接将旧的 fiber 树替换成新的 fiber 树&#xff0c;这样做的好处是省去了直接在页…

datax之channel学习

一般来说datax只需要我们设置reader和writer&#xff0c;但是是什么连接了reader和writer呢&#xff1f; 就是channel&#xff01; 这个有什么用&#xff1f; 慢慢学习。 core.json [devusercdp-node12 /data/DATA_DIR/share/dataingestion/conf]$ cat core.json { &quo…

应急物资仓库可视化管理系统-智慧应急物资装备管理系统

1. 项目概述 应急物资仓库可视化系统(智慧物资管理系统 DW-S300)是一套成熟系统&#xff0c;依托互 3D 技术、云计算、大数据、RFID 技术、数据库技术、AI、视频分析技术对 RFID 智能仓库进行统管理、分析的信息化、智能化、规范化的系统。 应急物资&#xff0c;是每当灾害发…

Cyanine7 NHS|CY7-N-羟基琥珀酰亚胺|CY7-NHS ester

Cyanine7 NHS|CY7-N-羟基琥珀酰亚胺|CY7-NHS ester 中文名称&#xff1a;CY7-N-羟基琥珀酰亚胺 英文名称&#xff1a;Cyanine7 NHS 性 状&#xff1a;深绿色粉末 分子量&#xff1a;827.94 Abs/Em Maxima&#xff1a;675/694nm 分子式&#xff1a;C41H46N3NaO10S2 溶解性…

【网站架构】项目越迭代越难、严重延期?那是没处理好变化

大家好&#xff0c;欢迎来到停止重构的频道。 本期&#xff0c;我们讨论网站系统的扩展性。 扩展性指的是网站系统应该如何更好地处理需求变化、版本迭代。 对于有几个项目经验的人来说&#xff0c;可能对这样的问题不以为然&#xff0c;毕竟devops、CI/CD、git、敏捷开发、…

Pytest测试框架(一):Pytest介绍与安装,Pytest编写规则及pytest.main()的参数

Pytest测试框架(1)&#xff1a;Pytest介绍与安装 pytest简介&#xff1a; pytest是python的第三方单元测试框架&#xff0c;比自带的unittest更简洁和高效&#xff0c;同时兼容unittest框架。 它还有如下优点&#xff1a; 1、简单灵活&#xff0c;容易上手&#xff0c;文档丰…

计算机毕业设计django基于python精品课程在线学习系统

项目介绍 在各学校的教学过程中,租房系统是一项非常重要的事情。随着计算机多媒体技术的发展和网络的普及。采用当前流行的B/S模式以及3层架构的设计思想通过Python技术来开发此系统的目的是建立一个配合网络环境的精品课程系统的平台,这样可以有效地解决课程学习系统混乱的局…

线上卡顿监控

文章目录1. 卡顿与ANR的关系2. 卡顿原理3. 卡顿监控3.1 WatchDog3.2 Looper Printer3.2.1 监控TouchEvent卡顿3.2.2 监控IdleHandler卡顿3.2.3 监控SyncBarrier泄漏4. 小结平时看博客或者学知识&#xff0c;学到的东西比较零散&#xff0c;没有独立的知识模块概念&#xff0c;而…

世界杯期间,抖音的涨粉秘诀是什么?

纵览11月抖音涨粉趋势&#xff0c;生活、体育、美食等领域有不少账号迅速圈粉。据新抖『粉丝飙升榜』TOP30显示&#xff0c;11月上榜达人的更替率高达83.3%&#xff0c;其中&#xff0c;有达人凭3条人物随拍视频涨粉千万&#xff1b;有达人凭硬核美食教程&#xff0c;被网友戏称…

网络工程毕业设计 SSM音乐管理系统(源码+论文)

文章目录1 项目简介2 实现效果2.1 界面展示3 设计方案3.1 概述3.2 系统流程3.2.1 系统开发流程3.3 系统结构设计4 项目获取1 项目简介 Hi&#xff0c;各位同学好呀&#xff0c;这里是M学姐&#xff01; 今天向大家分享一个今年(2022)最新完成的毕业设计项目作品&#xff0c;【…

【Python】基础语法 5(字典和文件)

1. 字典 1.1 字典是什么 字典是一种存储键值对的结构。 键值对是计算机/生活中一个非常广泛使用的概念。 把 键(key) 和 值(value) 进行一个一对一的映射, 然后就可以根据键, 快速找到值。 1.2 创建字典 创建一个空的字典&#xff0c;使用 { } 表示字典 a { } b dict() prin…

RabbitMQ之交换机

Exchanges概念 RabbitMQ消息传递模型的核心思想是&#xff1a;生产者生产的消息从不会直接发送到队列。实际上&#xff0c;通常生产者甚至都不知道这些消息传递到了哪些队列中。 相反&#xff0c;生产者只能将消息发送到交换机&#xff0c;交换机工作的内容很简单&#xff0c;…

【数据结构】详解七大排序算法(有源码)

目录☀️直接插入排序☀️希尔排序☀️直接选择排序☀️堆排序☀️冒泡排序☀️快速排序☀️归并排序☀️排序算法复杂度及稳定性分析☀️直接插入排序 1、基本思想 把待排序的数按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff0c;直到所以的记录插入完为止…

【设计模式】装饰者模式Decorator(Java)

文章目录1. 装饰者模式定义2. 类图3.Java实现3.1 饮料Beverage3.2 小料CondimentDecorator3.3 椰果Coconut3.4 红豆RedBean3.5 奶茶MikeTea3.6 果茶JuiceTea3.7 商店主方法StoreMain1. 装饰者模式定义 装饰者模式动态地将责任附加到对象上。若要扩展功能&#xff0c;装饰者提供…

享元模式

文章目录享元模式1.享元模式的本质2.何时选用享元模式3.优缺点4.享元模式的结构5.实现最初实现享元模式初步改造享元模式再改进享元模式再优化享元模式 享元模式最开始看就是类似缓存&#xff0c;缓存一些信息&#xff0c;节约查询时间&#xff0c;以空间换时间 但是再理解后才…

一行代码就能完成的事情,为什么要写两行

今天休息休息&#xff0c;复习一下使用的简洁运算方式以及常用的单行代码 三元运算符 用三元运算符代替简单的if else if (age < 18) {me 小姐姐; } else {me 老阿姨; } 改用三元运算符,一行就能搞定 me age < 18 ? 小姐姐 : 老阿姨; 复杂的判断三元运算符就有点…