18 优先级队列

priority_queue介绍

1.优先级队列是一种容器适配器,根据弱排序标准,它的第一个元素总是最大的
2.此上下文类似于堆,堆中可以随时插入元素,检索最大堆元素
3.优先队列实现为容器适配器,容器适配器即将特定容器类封装作为底层容器类,queue提供一组特定的成员函数访问其元素,元素从特定容器的“尾部”弹出,称为优先级队列的顶部
4.底层容器可以是任何标准容器类的模板,也可以是特定设计的容器类,容器应该可以通过随机访问迭代器访问,并支持以下操作:

  • empty (): 检测是否为空
  • size ():返回有效元素个数
  • top (): 返回第一个元素的引用
  • push_back (): 在容器尾部插入元素
  • pop_back (): 删除容器尾部元素
    5.标准容器类vector和deque满足这些要求,如果没有初始化容器,默认使用vector
    6.需要支持随机访问迭代器,以便始终保持内部结构,容器适配器需要时自动调用算法函数make_heap, push_heap 和 pop_heap完成操作

使用

函数声明接口说明
priority ()/priotirt queue (first, last)构造一个空队列
empty ()检测是否为空
top ()返回队列中堆顶的元素
push ()插入元素
pop ()删除堆顶元素

默认情况下是大堆

#include <vector>
#include <queue>
#include <functional> // greater算法的头文件
void TestPriorityQueue()
{// 默认情况下,创建的是大堆,其底层按照小于号比较vector<int> v{3,2,7,6,0,4,1,9,8,5};priority_queue<int> q1;for (auto& e : v)q1.push(e);cout << q1.top() << endl;// 如果要创建小堆,将第三个模板参数换成greater比较方式priority_queue<int, vector<int>, greater<int>> q2(v.begin(), v.end());cout << q2.top() << endl;
}

练习

数组第k大元素

在这里插入图片描述

解析

将数组排序返回倒数第k个就可以完成,但时间复杂度不够。可以用优先级队列,将数组里的元素插入队列,弹k-1次队列,堆顶就是第k大的元素

class Solution {
public:int findKthLargest(vector<int>& nums, int k) {priority_queue<int> que;for (auto ch : nums) {que.push(ch);}while (--k) {que.pop();}return que.top();}
};

这种解法时间复杂度是O(k*logN + N),如果N远大于k,复杂度也会变高,可以优化一下,只用前k个元素建堆,比较数组剩下元素,更大的进堆,这样空间和效率都会好很多

先建立一个小堆的优先队列,前k个元素。从数组第k个元素开始遍历,比堆顶大就替换进去,先出堆顶再入堆。这样堆里就是整个数组前k大的元素,第k大的就是堆顶的元素

class Solution {
public:int findKthLargest(vector<int>& nums, int k) {priority_queue<int, vector<int>, greater<int>> que(nums.begin(),nums.begin() + k);for (int i = k; i < nums.size(); i++) {if (nums[i] > que.top()) {que.pop();que.push(nums[i]);}}return que.top();}
};

实现

既然是容器适配器,成员函数就是模板的容器,调用对应的功能。结构是堆,在插入调用容器的插入功能后,要向上调整堆。删除堆顶元素后,要向下调整堆,保证堆顶元素时最值。看看标准库需要什么模板
在这里插入图片描述

首先是变量的类型,容器的种类,最后是一个仿函数

仿函数

仿函数的本质是一个类,它重载了函数调用符 () ,当这个类的对象使用()时,就调用了自己写的函数

优先队列需要两个仿函数,是大小比较的,一个从小到大,一个从大到小。传入模板T类型返回比较结果

	template <typename T>struct less{bool operator()(const T& x1, const T& x2){return x1 < x2;}};

有了仿函数,优先队列的类的写法和之前的栈这些一样,只需要调用容器对应的功能。调整堆的写法在数据结构展示过,过程基本差不多,这是大小比较这里用仿函数

在这里插入图片描述

代码

#pragma oncenamespace my_queue
{template <typename T>struct less{bool operator()(const T& x1, const T& x2){return x1 < x2;}};template <typename T>struct greater{bool operator()(const T& x1, const T& x2){return x1 > x2;}};template <class T, class container = vector<T>, class compare = less<T>>class priority_queue{public:void adjust_up(int child){compare com;int parent = (child - 1) / 2;while (child > 0){if (com(_con[parent], _con[child])){swap(_con[child], _con[parent]);}else{return;}child = parent;parent = (child - 1) / 2;}}void adjust_down(int parent){compare com;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])){swap(_con[child], _con[parent]);}else{break;}parent = child;child = parent * 2 + 1;}}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);}T& top(){return _con[0];}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:container _con;};
}

仿函数的用法

对于自定义类,这里的仿函数会调用类的比较的重载。而对于类的指针,仿函数不一定只能用默认的大小比较,也可以自己实现一个仿函数,传入优先队列,就会调用自己的比较功能

下面是一个日期类

class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}bool operator<(const Date& d)const{return (_year < d._year) ||(_year == d._year && _month < d._month) ||(_year == d._year && _month == d._month && _day < d._day);}bool operator>(const Date& d)const{return (_year > d._year) ||(_year == d._year && _month > d._month) ||(_year == d._year && _month == d._month && _day > d._day);}friend ostream& operator<<(ostream& _cout, const Date& d){_cout << d._year << "-" << d._month << "-" << d._day;return _cout;}
private:int _year;int _month;int _day;
};

实现仿函数,传入优先队列,就可以自己实现比较功能

//仿函数
struct __date_less
{bool operator()(const Date* d1, const Date* d2){return *d1 < *d2;}
};
//传入
priority_queue <Date*, vector<Date*>, __date_less> que;que.push(new Date(2018, 10, 29));
que.push(new Date(2018, 10, 28));
que.push(new Date(2018, 10, 30));
cout << *(que.top()) << endl;

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

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

相关文章

基于vue实现bilibili网页

学校要求的实验设计,基于vue实现bilibili网页版,可实现以下功能 (1)基本的悬浮动画和页面渲染 (2)可实现登录和未登录的页面变化 (3)在登录页面的,实现密码判断,或者短信验证方式的倒数功能 (4)实现轮播图 (5)实现预览视频(GIF) (6)页面下拉到一定高度出现top栏以及右下角的返回…

蓝桥杯单片机快速开发笔记——超声波测距

一、原理分析 超声波测距是一种常见的测距方法&#xff0c;其原理是利用超声波在空气中传播的速度恒定且较快的特性&#xff0c;通过发送超声波信号并接收回波&#xff0c;计算出物体与传感器之间的距离。以下是超声波测距的原理和应用&#xff1a; 原理&#xff1a; 发送超声…

gma 2.0.7 (2024.03.16) 更新日志

安装 gma 2.0.7 pip install gma2.0.7网盘下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1P0nmZUPMJaPEmYgixoL2QQ?pwd1pc8 提取码&#xff1a;1pc8 注意&#xff1a;此版本没有Linux版&#xff01; 编译gma的Linux虚拟机没有时间修复&#xff0c;本期Linux版继…

hadoop分布式环境搭建

准备三台centos虚拟机 。&#xff08;master&#xff0c;slave1&#xff0c;slave2&#xff09; (hadoop、jdk文件链接&#xff1a;https://pan.baidu.com/s/1wal1CSF1oO2h4dkSbceODg 提取码&#xff1a;4zra) 前四步可参考hadoop伪分布式环境搭建详解-CSDN博客 1.修改主机名…

论文阅读——MoCo

Momentum Contrast for Unsupervised Visual Representation Learning 动量在数学上理解为加权移动平均&#xff1a; yt-1是上一时刻输出&#xff0c;xt是当前时刻输入&#xff0c;m是动量&#xff0c;不想让当前时刻输出只依赖于当前时刻的输入&#xff0c;m很大时&#xff0…

pytorch升级打怪(六)

自动分化 torch.autograd张量、函数和计算图计算梯度禁用梯度跟踪 torch.autograd 在训练神经网络时&#xff0c;最常用的算法是反向传播。在该算法中&#xff0c;根据损失函数相对于给定参数的梯度调整参数&#xff08;模型权重&#xff09;。 为了计算这些梯度&#xff0c;…

软件测试6年,我的心路历程。。。

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 现在的大环境下&#xff0c;各行各业都开始内卷起来&#xff0c;测试也不例外&#xff0c;企业要…

LeetCode——两数相加

目录 一、两数相加 1、题目 2、题目解读 3、代码 二、反转链表 1、题目 2、题目解读 3、代码 三、两数相加 II 1、题目 2、题目解读 3、代码 反转链表再进行计算 借助栈 一、两数相加 1、题目 2. 两数相加 - 力扣&#xff08;Leetcode&#xff09; 给你两个 非…

MS16_016 漏洞利用与安全加固

文章目录 环境说明1 MS16_016 简介2 MS16_016 复现过程3 MS16_016 安全加固 环境说明 渗透机操作系统&#xff1a;kali-linux-2024.1-installer-amd64漏洞复现操作系&#xff1a;cn_windows_7_professional_with_sp1_x64_dvd_u_677031 1 MS16_016 简介 MS16_016 漏洞产生的原因…

WebServer -- 八股(终章)

&#x1f442; Honey Honey - 孙燕姿 - 单曲 - 网易云音乐 目录 &#x1f33c;触类旁通 &#x1f6a9;线程 && 进程 线程与进程的区别 多线程锁是什么 进程 / 线程 / 协程 的区别 线程切换时&#xff0c;需要切换的状态 &#x1f382;并发 && 并行 并…

Java基础夯实——八股文【2024面试题案例代码】

1、Java当中的基本数据类型 Java中常见的数据类型及其对应的字节长度和取值范围如下&#xff1a; byte&#xff1a;1字节&#xff0c;取值范围为-128到127。short&#xff1a;2字节&#xff0c;取值范围为-32,768到32,767。int&#xff1a;4字节&#xff0c;取值范围为-2,147…

【数据挖掘】练习2:数据管理2

课后作业2&#xff1a;数据管理2 一&#xff1a;上机实验2 # 编写函数stat&#xff0c;要求该函数同时计算均值&#xff0c;最大值&#xff0c;最小值&#xff0c;标准差&#xff0c;峰度和偏度。 install.packages("timeDate") library(timeDate) stat <- func…

Swagger Array 使用指南:详解与实践

Swagger 允许开发者定义 API 的路径、请求参数、响应和其他相关信息&#xff0c;以便生成可读性较高的文档和自动生成客户端代码。而 Array &#xff08;数组&#xff09;是一种常见的数据结构&#xff0c;用于存储和组织多个相同类型的数据元素。数组可以有不同的维度和大小&a…

腾讯钟学丹:人工智能成为汽车行业新质生产力 推动数智化升级

近日&#xff0c;在中国电动汽车百人会论坛&#xff08;2024&#xff09;新质生产力分论坛上&#xff0c;腾讯智慧出行副总裁钟学丹发表了题为《AI驱动汽车“新智能”》的主题演讲&#xff0c;分享了腾讯AI大模型等新技术在汽车产业的创新应用成果。 腾讯智慧出行副总裁钟学丹 …

【鸿蒙HarmonyOS开发笔记】如何使用图片插帧将低像素图片清晰放大

开发UI时&#xff0c;当我们的原图分辨率较低并且需要放大显示时&#xff0c;图片会模糊并出现锯齿。如下图所示 这时可以使用interpolation()方法对图片进行插值&#xff0c;使图片显示得更清晰。该方法的参数为ImageInterpolation枚举类型&#xff0c;可选的值有: ImageInte…

主键约束

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 主键约束可以看成是非空约束再加上唯一约束 也就是说设置为主键列&#xff0c;不能为空&#xff0c;不能重复 像一般用户编号是不可能重复的&#xff0c;也不可能为空的 …

C#开发中方法使用的问题注意

C#开发中&#xff0c;我们在进行方法内嵌时&#xff0c;需要注意方法回传带值时&#xff0c;我们需要对方法回传的值进行一个赋值传递 如下所示 console.WriteLine("请输入你的爱好&#xff1a;"); string aihao Console.ReadLine(); name ChangeData(name);同时在…

找不到msvcp110.dll怎么办,msvcp110.dll丢失的5种修复方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp110.dll丢失”。由于msvcp110.dll是Microsoft Visual C Redistributable Package的重要组成部分&#xff0c;它的缺失会导致依赖于该组件的软件无法正常启动或运行&#xff0c;比如某…

Java开发者的新宠:探索轻量级且功能强大的Magic-API

Java开发者的新宠&#xff1a;探索轻量级且功能强大的Magic-API 一、Magic-API简介二、Magic-API的核心特性三、结语 大家好&#xff0c;这里是程序猿代码之路&#xff0c;在当今的软件开发领域&#xff0c;快速迭代和高效交付是每个项目追求的目标。对于Java开发者来说&#x…

汽车电子零部件(7):电机Motor

前言: 新能源汽车的三大件是:电池、电机、电控。可见电机的重要性,可以说直接就取代了发动机。而用到电机的地方不仅仅有驱动四轮,还有方向盘、门窗甚至电池热管理等也都是需要电机这个器件的。当然就电机而言又分变频电机和直流电机,有刷电机和无刷电机。从架构上说,需…