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.hqwc.cn/news/548766.html

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

相关文章

代码随想录|Day23|回溯03|39.组合总和、40.组合总和II、131.分割回文串

39.组合总和 本题和 216.组合总和III 类似&#xff0c;但有几个区别&#xff1a; 没有元素个数限制&#xff1a;树的深度并不固定&#xff0c;因此递归终止条件有所变化每个元素可以使用多次&#xff1a;下层递归的起始位置和上层相同&#xff08;startIndex不需要改动&#xf…

PostgreSQL中vacuum 物理文件truncate发生的条件

与我联系&#xff1a; 微信公众号&#xff1a;数据库杂记 个人微信: iiihero 我是iihero. 也可以叫我Sean. iiheroCSDN(https://blog.csdn.net/iihero) Sean墨天轮 (https://www.modb.pro/u/16258) 数据库领域的资深爱好者一枚。 水木早期数据库论坛发起人 db2smth就是俺&am…

特约撰稿 | 李杰:2024快消品牌企业如何赢在数字化?

随着用户群体、消费场景的细分&#xff0c;以及渠道的进一步多元化&#xff0c;让快消品企业遇到了一些机遇与挑战&#xff0c;在这样的大趋势之下&#xff0c;2024年快消品牌企业&#xff0c;要脱颖而出赢得增长&#xff0c;必须要把握战略上的机会。 作者&#xff5c;纷享销…

苍穹外卖-day09:用户端历史订单模块(理解业务逻辑),商家端订单管理模块(理解业务逻辑),校验收货地址是否超出配送范围(相关API)

用户端历史订单模块 1. 查询历史订单&#xff08;分页查询&#xff09; 1.1 需求分析和设计 产品原型&#xff1a; 业务规则 分页查询历史订单可以根据订单状态查询展示订单数据时&#xff0c;需要展示的数据包括&#xff1a;下单时间、订单状态、订单金额、订单明细&#…

探寻源码宝藏:介绍开源项目“source-code-hunter“

最近处于金三银四的面试黄金期&#xff0c;许多同学在面试中反映现在要求非常高&#xff0c;阅读源码几乎是必问项。然而&#xff0c;阅读源码时常常觉得晦涩难懂&#xff0c;令人头疼。今天在浏览 GitHub 时&#xff0c;我发现了一个名为 source-code-hunter 的宝藏项目。这个…

苍穹外卖-day06:HttpClient、微信小程序开发、微信登录(业务流程)、导入商品浏览功能代码(业务逻辑)

苍穹外卖-day06 课程内容 HttpClient微信小程序开发微信登录导入商品浏览功能代码 功能实现&#xff1a;微信登录、商品浏览 微信登录效果图&#xff1a; 商品浏览效果图&#xff1a; 1. HttpClient 1.1 介绍 HttpClient 是Apache Jakarta Common 下的子项目&#xff0c;…

在Linux系统中如何查询日志?

在工作中&#xff0c;我们有时候会定位问题&#xff0c;这时候就需要查询日志了&#xff0c;那么查询日志的命令有哪些呢&#xff1f; cat 查看某个日志文件中的所有内容。 使用示例&#xff1a;cat file.txt 显示 file.txt 文件的所有内容。 如果要对查询的结果进行筛选&am…

代码随想录算法训练营第11天| 20. 有效的括号,1047. 删除字符串中的所有相邻重复项,150. 逆波兰表达式求值

系列文章目录 目录 系列文章目录20. 有效的括号利用栈对称匹配将栈中元素弹出与判断栈顶元素是否匹配分开&#xff0c;比较耗时&#xff08;2ms)&#xff1a;若将栈中元素弹出与判断栈顶元素是否匹配放一起&#xff0c;比较节省时间(1ms)&#xff1a; 1047. 删除字符串中的所有…

解决:visio导出公式为pdf图片乱码问题

今天需要将Visio编辑好的以后的图输出pdf&#xff0c;但是点击保存后公式部分一直乱码&#xff0c;如下图所示 保存为pdf后会变成&#xff1a; 解决方案&#xff1a;保存时点击文件下方的快速打印&#xff0c;存到桌面&#xff0c;不要直接点击保存

苍穹外卖-day10:Spring Task、订单状态定时处理、来单提醒(WebSocket的应用)、客户催单(WebSocket的应用)

苍穹外卖-day10 课程内容 Spring Task订单状态定时处理WebSocket来单提醒客户催单 功能实现&#xff1a;订单状态定时处理、来单提醒和客户催单 订单状态定时处理&#xff1a; 来单提醒&#xff1a; 客户催单&#xff1a; 1. Spring Task 1.1 介绍 Spring Task 是Spring框…

Python AI 之PhotoMaker 安装总结

PhotoMaker 官方文档 PhotoMaker GitHub 地址:https://github.com/TencentARC/PhotoMaker PhotoMaker Windows 安装 温馨提示&#xff1a;PhotoMaker 官网github 版本为通用版本&#xff0c;如果是Windows系统安装PhotoMarker 需要使用截图下的版本&#xff1a; 第一步&am…