【STL】priority_queue的使用及模拟实现

news2025/2/1 17:57:35

目录

前言

priority_queue的使用

功能解析

基本接口

写点题目

模拟实现

结构解析

插入删除

调整函数结合仿函数

仿函数介绍

结合使用

其他功能

接口补齐

迭代器区间构造


前言

🍾打开 queue 头文件后,我们发现除了我们之前介绍过的普通队列以外,还有一个 priority_queue

🍾其又名为优先级队列,之所以叫这个名字正是因为这个队列出队时会根据某种优先级弹出元素

🍾听到这个功能是不是觉得有点耳熟,这不就跟我们以前写过的堆一模一样吗?实际上便可以将其当作是库中封装的堆,同时配合模板使其具有更多的自由度。


priority_queue的使用

功能解析

在使用 priority_queue 之前,我们先看一下文档中的内容,模板中有三个参数,分别是内置数据类型内置容器仿函数

🍾后面两个参数默认有缺省值,直接使用缺省值便是使用 vector 适配构建一个大堆

[注意] 这里的内置容器可以使用vector和deque,不能使用list。

int main()
{
	priority_queue<int> pq1;    //内部数据类型为int,数据类型为vector,构建大堆
	priority_queue<int, deque<int>> pq2; //内部数据类型为int,数据类型为deque,构建大堆
	priority_queue<int, vector<int>, greater<int>> pq3; //内部数据类型为int,数据类型为vector,构建小堆
	return 0;
}

基本接口

🍾接口的命名方式与 stack 和 queue 接近,访问第一个元素是 top 而不是 front 不要和 queue 记混了。

🍾下面通过实例代码简单使用一下:

int main()
{
	priority_queue<int> pq;    //内部数据类型为int,数据类型为vector,构建大堆
	pq.push(1);    //插入数据
	pq.push(0);
	pq.push(5);
	pq.push(2);
	pq.push(1);
	pq.push(7);

	while (!pq.empty())   //直到堆为空之前循环
	{
		cout << pq.top() << " ";  //打印堆顶
		pq.pop();     //弹出元素
	}
	return 0;
}

🍾之后就是根据从大到小的顺序进行输出。 

 

🍾现在我们使用迭代器区间构造小堆,最后输出的结果便是从小到大的。

int main()
{
	int a[] = { 5,4,8,2,5,7,3,9 };
	priority_queue<int, vector<int>, greater<int>> pq(a, a + 8); //使用迭代器区间构造

	while (!pq.empty())   //直到堆为空之前循环
	{
		cout << pq.top() << " ";  //打印堆顶
		pq.pop();     //弹出元素
	}
	return 0;
}

写点题目

🍾又得将我们 Kvalue 这个题目拎出来了,以前写的时候我们还要自己手搓一个堆出来,今非昔比,我们可以直接使用库里的堆了。

🍾要求出第大 k 的值,那我们不妨维护一个 k 个值的堆让数组之后的每一个值都与堆顶元素进行对比,只有比堆顶元素大的元素才插入。同时,为了维护这个效果堆顶元素必须使整个堆中最小的那个元素,因此构建小堆。遍历完整个数组后,堆顶元素就是我们要求的目标值。

int findKthLargest(vector<int>& nums, int k) {
    priority_queue<int, vector<int>, greater<int>> pq(nums.begin(),nums.begin()+k);   //以数组前k个值构建小堆
    for (int i = k; i < nums.size(); i++)   //遍历数组
    {
        int t = pq.top();  
        if(nums[i]>t)      //比堆顶元素大先删除原堆顶元素,再插入
        {
            pq.pop();
            pq.push(nums[i]);
        }
    }
    return pq.top();
}

模拟实现

🍾priority_queue 的模拟实现本质上就是借助仿函数和模板对堆进行封装,与之前的讲解侧重点可能不同。

🍾更多细节可以去这里复习一下,堆及堆排序的实现。

结构解析

🍾根据模板参数定义内置容器和仿函数的对象,而仿函数在下面会进行讲解。

namespace Alpaca
{
    template<class T,class Container = vector<T>,class Compare = less<T>>
	class priority_queue
	{
	public:
    private:
		Container _con;     //内置容器
		Compare com;        //仿函数
	};
}

插入删除

🍾在之前实现堆的时候,插入和删除的操作都是在数组尾部进行的

🍾插入时就直接插入到数组尾,之后再向上调整,而删除需要将堆顶的数据交换到数组尾部,再进行删除,同时,交换上去的那个数需要进行向下调整

void push(const T& x)
{
	_con.push_back(x);
	adjust_up(_con.size()-1);
}

void pop()
{
	std::swap(_con[0], _con.back());
	_con.pop_back();
	adjust_down(0);
}

调整函数结合仿函数

仿函数介绍

🍾在讲这部分之前先简单介绍一下仿函数,我们在一个类中只进行 ( ) 运算符重载,这之后我们便可以像使用函数一样使用这个类。

🍾如下,我实现一个仿函数用于判断两个值的大小。

struct judge     //直接使用struct定义类使成员函数默认为共有访问的
{
	bool operator ()(const int x, const int y)
	{
		return x > y;
	}
};

int main()
{
	int a = 8, b = 7;
	judge jud;                      //实例化对象
	cout << jud(a, b) << endl;
	cout << judge()(a, b) << endl;  //使用匿名对象
	return 0;
}

🍾实际上便于函数指针相像,但使用起来会相较函数指针更加简单一些。

🍾之前我们写堆的时候一次只能写一份构建的大堆小堆也是写死的,使用了仿函数后便可以将生成的选项交给使用者选择。

🍾将调整函数与仿函数结合起来就是接下来我们关注的重点。

结合使用

🍾一个值在数组尾插入后需要根据优先级在堆中找到其对应的位置,因此要进行向上调整,但在以前构建大堆还是小堆是我们在写的时候直接写死的,这里我们就要结合仿函数进行实现。于是在判断时我们便可直接沿用仿函数的返回值,而仿函数的选择由用户决定

🍾这样便可由用户自主决定构建出来的是大堆还是小堆,高自由度的同时还能够支持自定义类型的比较(仿函数也可以由用户构建)。

template<class T>    //沿用了库中仿函数的命名规则
struct greater
{
	bool operator ()(const T& x, const T& y)
	{
    	return x > y;
	}
};

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

🍾自己实现仿函数后便可以将其带入到调整函数中去了,同时由于我们在成员变量中定义对象了,因此这里直接使用即可。

void adjust_up(int child)
{
	int parent = (child - 1) / 2;               //向上找父亲
	while (child > 0)
	{
		if (com(_con[parent], _con[child]))     //判断是否符合优先级
		{
			std::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], _con[child + 1]))  //根据优先级找最符合的还在
		{
			child++;
		}

		if (com(_con[parent], _con[child]))      //判断是否符合优先级
		{
			std::swap(_con[parent], _con[child]);  //符合则交换
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

其他功能

接口补齐

🍾之后将剩余的接口补齐即可,分别是堆顶元素、堆的大小、判空和交换。

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

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

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

void swap(priority_queue& pq)
{
	_con.swap(pq._con);
}

迭代器区间构造

🍾在看文档的时候,还看到通过迭代器区间进行构造,于是便简单实现一下,同时还要写一个无参的默认构造函数。

priority_queue()
{}

template<class interator>
priority_queue(interator begin, interator end)  //迭代器区间构造
{
	while (begin != end)
	{
		push(*begin);            //将每个值push进堆中
		begin++;
	}
}

🍾好了,今天 priority_queue基本使用和模拟实现 的相关内容到这里就结束了,如果这篇文章对你有用的话还请留下你的三连加关注。

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

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

相关文章

用maven安装JUnit 5并运行单元测试

一&#xff1a;首先讲如何安装 JUnit 5 JUnit Platform JUnit Jupiter JUnit Vintage 如果不需要执行基于JUnit 3 和JUnit 4 的用例&#xff0c;那么JUnit Vintage就不需要安装。 1&#xff09;在pom文件dependencies的小节内增加如下依赖&#xff1a; <dependency>&l…

Docker安装ClickHouse22.6.9.11并与SpringBoot、MyBatisPlus集成

背景 上一篇文章CentOS6.10上离线安装ClickHouse19.9.5.36并修改默认数据存储目录记录了在旧版的操作系统上直接安装低版本 ClickHouse &#xff08;脱胎于俄罗斯头号搜索引擎的技术&#xff09;的过程&#xff0c;开启远程访问并配置密码&#xff1b; 其实通过 Docker 运行 …

一文读懂性能测试

01、常见概念 吞吐量&#xff08;TPS, QPS&#xff09; 简单来说就是每秒钟完成的事务数或者查询数。通常吞吐量大表明系统单位时间能处理的请求数越多&#xff0c;所以通常希望TPS越高越好 响应时间 即从请求发出去到收到系统返回的时间。响应时间一般不取平均值&#xff0…

二叉树及其链式结构

目录 一&#xff1a;树概念及结构 1.树的概念 2.树的相关概念 3.树的表示 二&#xff1a;二叉树的概念及结构 1.概念 2.特殊的二叉树 <1>. 满二叉树&#xff1a; <2>. 完全二叉树&#xff1a; 3.二叉树的性质 4.二叉树的存储结构 <1>.顺序结构 <…

win11 无法登录微软账户 终极解决方案

背景&#xff1a;win11突然无法登录微软账户&#xff0c;office无法激活&#xff0c;Edge里的微软账户也无法登录&#xff0c;反馈中心也无法打开等&#xff0c;有网络&#xff0c;浏览器可以访问微软并进行登录。 试过网上的网络配置&#xff08;SSL及TLS协议勾选&#xff09…

数学模型:Python实现线性规划

文章摘要&#xff1a;线性规划的Python实现。 参考书籍&#xff1a;数学建模算法与应用(第3版)司守奎 孙玺菁。 PS&#xff1a;只涉及了具体实现并不涉及底层理论。学习底层理论以及底层理论实现&#xff1a;可以参考1.最优化模型与算法——基于Python实现 渐令 粱锡军2.算法导…

vim复制,剪切觉得麻烦?今天就来教会你:vim复制和剪切教程

上次讲了vim移动光标的快捷键&#xff0c;今天我们来了解一下vim的复制多行的功能。 快速复制多行 第一步&#xff1a;将光标移动到复制的文本开始的地方&#xff0c;按下v进入可视模式&#xff0c;这里的v的意思就是visual的缩写&#xff0c;就是可视的意思。 第二步&#x…

DBSCAN 集群

目录 DBSCAN 集群 主要代码 DBSCAN 绘制结果中的集群 DBSCAN 集群 基于密度的空间聚类应用&#xff08;DBSCAN&#xff09;是一种基于密度的聚类算法&#xff0c;由Martin Ester等人在1996年提出。该算法在半径为ε的圆内找到数据点的相邻点&#xff0c;并将它们加入到同一…

Git原理详解+指令操作,带你快速掌握Git

一、相关概念 版本控制 什么是版本控制&#xff1f; 用于管理多人协同开发项目的技术对文件的版本控制&#xff0c;要对文件进行修改、提交等操作 版本控制的分类 1.本地版本控制 就是放在本地 2.集中版本控制 SVN 所有的版本数据都保存在服务器上&#xff0c;协同开发…

GDAL读取属性表值乱码解决方法

文章目录 方法1&#xff1a;方法2&#xff1a;1.通过在线网网站&#xff0c;查看编码2.参考C中gbk和utf8互相转换文章 gdal示例代码 方法1&#xff1a; 在网上查看的推荐方法&#xff08;C代码&#xff09;&#xff0c;但没解决我遇到的问题&#xff1b; CPLSetConfigOption(&…

SSM整合快速入门案例

文章目录 前言一、设计数据库表二、创建工程三、SSM技术整合四、功能模块开发五、接口测试总结 前言 为了巩固所学的知识&#xff0c;作者尝试着开始发布一些学习笔记类的博客&#xff0c;方便日后回顾。当然&#xff0c;如果能帮到一些萌新进行新技术的学习那也是极好的。作者…

Java网络开发(Tomcat)——登陆和注册功能 的 迭代升级 从Jsp到JavaScript + axios + vue 诸多bug 同步到异步

目录 引出前置工作vueaxiosresp0.vue版本的jsp模板1.导包--Json&#xff1a;pom.xml文件&#xff1a;2.新建一个专门用来处理响应的实体类ResData3.在axios中&#xff0c;所有响应必须是 resp.getWriter().write() 的方式&#xff0c;核心代码如下4.在jsp前端代码中导包&#x…

华为OD机试真题B卷 JavaScript 实现【查字典】,附详细解题思路

一、题目描述 输入一个单词前缀和一个字典&#xff0c;输出包含该前缀的单词。 二、输入描述 单词前缀字典长度字典。 字典是一个有序单词数组。 输入输出都是小写。 三、输出描述 所有包含该前缀的单词&#xff0c;多个单词换行输出。 若没有则返回-1。 四、解题思路…

SLAM十四讲——ch3实践

ch3的实践及避坑 一、ch3的总体步骤二、文件的执行1. 实践&#xff1a;Eigen2. 实践&#xff1a;Eigen几何模块3. 可视化演示 出现的问题 一、ch3的总体步骤 确保已经安装Eigen库&#xff0c;Eigen库是一个C开源线性代数库。 sudo apt-get install libeigen3-dev说明&#xf…

在 Compose 中实现缓存列表数据提升用户体验(Stale-while-revalidate)

前言 最近在利用业余时间使用 Compose 实现一个 Github APP 客户端。 对标的是 GSY 大佬使用多种不同语言框架实现的 Github APP。 在实现过程中发现一些问题&#xff0c;因为这个客户端的数据几乎全部来自于 Github API&#xff0c;所以 UI 渲染也极度依赖于请求到的数据。…

JAVA面向对象(三)

第三章 封装与继承 目录 第三章 封装与继承 1.1.封装 1.2.包 1.3.访问权限控制 1.4.static修饰符 1.4.1.成员变量 1.4.2.成员方法 1.4.3.代码块 总结 内容仅供学习交流&#xff0c;如有问题请留言或私信&#xff01;&#xff01;&#xff01;&#xff01;&#xff0…

java并发编程:ArrayBlockingQueue详解

文章目录 一、简介二、数据结构三、源码分析3.1 属性3.2 构造方法3.3 方法3.3.1 入队3.3.2 出队3.3.3 获取元素3.3.4 删除元素 四、总结 一、简介 ArrayBlockingQueue 顾名思义&#xff1a;基于数组的阻塞队列。数组是要指定长度的&#xff0c;所以使用 ArrayBlockingQueue 时…

在知乎逮到一个腾讯10年老测试,聊过之后收益良多...

老话说的好&#xff0c;这人呐&#xff0c;一单在某个领域鲜有敌手了&#xff0c;就会闲得蛋疼。前几天我在上班摸鱼刷知乎的时候认识了一位腾讯测试大佬&#xff0c;在腾讯工作了10年&#xff0c;因为本人天赋比较高&#xff0c;平时工作也兢兢业业&#xff0c;现在企业内有一…

Python基础知识讲解——main方法

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 估计很多人跟我一样初学python看代码的时候先找一下main()方法&#xff0c;从main往下看。 但事实上python中是没有你理解中的“main()”方法的。 言归正传 if name "main":可以看成是python程序的入口&a…

数据结构与算法系列之习题练习

&#x1f497; &#x1f497; 博客:小怡同学 &#x1f497; &#x1f497; 个人简介:编程小萌新 &#x1f497; &#x1f497; 如果博客对大家有用的话&#xff0c;请点赞关注再收藏 &#x1f31e; 力扣习题 括号匹配问题。用队列实现栈。用栈实现队列。设计循环队列。 有效的括…