priority_queue的使用以及模拟实现
前言
上一期我们对stack和queue进行了使用的介绍,以及对底层的模拟实现!以及容器适配器做了介绍,本期我们在来介绍一个容器适配器priority_queue!
本期内容介绍
priority_queue的使用
仿函数介绍
priority_queue的模拟实现
什么是priority_queue?
priority_queue称为优先级队列,实际上就是堆(如果忘了什么是堆, 请点击这里)!它也是容器适配器,底层默认的容器是vector,默认是大堆!
常用的接口介绍
empty
判断是否为空
size
元素的个数
top
获取堆顶元素
注意:堆顶元素是不允许修改的,如果修改了会影响整个堆的结构,所以用const修饰!!
push
插入一个新元素
pop
删除堆顶的元素
OK,用一下!
void test()
{priority_queue<int> pq;pq.push(2);pq.push(15);pq.push(-1);pq.push(90);size_t sz = pq.size();cout << sz << endl;bool empty = pq.empty();cout << empty << endl;int top = pq.top();cout << top << endl;while (!pq.empty()){cout << pq.top() << " ";pq.pop();}
}
priority_queue在是很有用的,例如TopK问题和堆排序。堆排序不在介绍,在数据结构已经详细的介绍了,这里拿个题目来再次理解一下TopK:
数组中第K大元素
它的题目意思就是让你,找出第K大的元素,但是要求时间度杂度O(N)!
思路:这里有三种, 第三种最优。
1、利用排序数组,然后返回倒数k个元素即可!
2、借助堆
3、快速选择算法(算法专栏介绍)
我们这里就先介绍前两种!
1、利用排序数组,然后返回倒数k个元素即可!(时间复杂度不符合)
class Solution {
public:int findKthLargest(vector<int>& nums, int k) {sort(nums.begin(), nums.end());return nums[nums.size() -k ];}
};
这里虽然过了,但是这个代码的时间复杂度是O(N*logN),不符合!
2、借助堆
class Solution {
public:int findKthLargest(vector<int>& nums, int k) {priority_queue<int> pq(nums.begin(), nums.end());//将数组的元素放到堆里面for(int i = k; i > 1; i--)//将前k-1个弹出堆{pq.pop();}return pq.top();//返回堆顶的元素}
};
OK,这就过了,但是时间复杂度也是不行的!也还是O(N*logN)。最优解在后续的算法专栏会介绍!这主要是主要是演示一下堆在OJ中的用法~!
仿函数介绍
仿函数是一种类,它的对象可以向函数一样被调用。他是一种可调用对象,可以向像函数一样接收参数并返回结果!通常情况,仿函数是通过一个类实现operator ()来实现的!
例如,上面刚介绍的priority_queue:
这里的less就是一个仿函数!还有就是sort:
OK,举个仿函数的例子:
struct cmp
{bool operator()(const int& a, const int& b){return a < b;}
};//class cmp
//{
//public:
// bool operator()(const int& a, const int& b)
// {
// return a < b;
// }
//};void test()
{cmp cm;int result1 = cm(3, 5);int result2 = cm.operator()(3, 5);int result3 = cmp()(3, 5);
}
第一种和第二种本质是同一种,第二种是第一种的显示调用,第三种是匿名对象调用!当然这里的struct可以是class但注意的是如果是class你必须吧权限设置为public!
仿函数的用途
仿函数的用途我目前碰到的有两种(后面遇见了在补充):
1、STL算法库中的某些算法来用 仿函数定义他们的行为!例如:sort等
2、容器的自定义行为!例如priority_queue指定大小堆!等
#include <algorithm>
template<class T>
struct Compare
{bool operator() (const T& a, const T& b){return a > b;}
};void test()
{ vector<int> v = { 1,3,0,12,43,5,9 };sort(v.begin(), v.end());//默认是升序for (const auto& e : v){cout << e << " ";}cout << endl;sort(v.begin(), v.end(), Compare<int>());//降序 --》用匿名对象Compare<int> cmp;sort(v.begin(), v.end(), cmp);//降序 --》用实名对象for (const auto& e : v){cout << e << " ";}cout << endl;
}
大堆和小堆
void test()
{vector<int> v = { 0,12,43,5,9 };priority_queue<int> pq1(v.begin(), v.end());//默认大堆while (!pq1.empty()){cout << pq1.top() << " ";pq1.pop();}cout << endl;priority_queue<int, vector<int>, greater<int>> pq2(v.begin(), v.end());//指定为小堆while (!pq2.empty()){cout << pq2.top() << " ";pq2.pop();}cout << endl;
}
这里priority_queue默认是less:
template <class T, class Container = vector<T>, class Compare = less<typename Container::value_type> > class priority_queue;
如果要切换为小堆,就得指定仿函数为greater,但是我们知道参数是倒着(从右往左)传递的,所以这里要指定为小堆的话,还要指定它的底层适配的容器~!一般是vector也可以是deque!!
priority_queue的模拟实现
priority_queue()
{}bool empty() const
{return _con.empty();
}size_t size() const
{return _con.size();
}const T& top() const
{return _con.front();
}
这几个不在多说,很简单直接调用默认容器的相关接口即可~!主要介绍一下这里的插入、删除和用用一段迭代器区间构造!
push
先插入到适配容器的尾部,然后进行向上调整!(向上调整不了解的点击上面介绍对那个文章的链接回忆一下)
另外注意的是这里我们不再是以前的大于小于比较了,而是用仿函数!
void adjust_up(size_t child)
{size_t parent = (child - 1) / 2;while (child > 0){if (cmp()(_con[parent], _con[child]))//孩子比父亲大(小),交换{swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;//否则,结束掉}}
}
void push(const T& val)
{_con.push_back(val);adjust_up(_con.size() - 1);
}
pop
先交换堆顶数据和最后一个数据!然后删除掉,堆顶数据,进行向下调整~!(向下调整和向上调整一样,详细见数据结构那里)
另外注意的是这里我们不再是以前的大于小于比较了,而是用仿函数!
void adjust_down(size_t parent)
{size_t child = parent * 2 + 1;//假设第一个孩子就是要交换的孩子while (child < _con.size()){if (child + 1 < _con.size() && cmp()(_con[child], _con[child + 1]))//假设错了{++child;//调整}if (cmp()(_con[parent], _con[child]))//孩子比父亲大(小){swap(_con[parent], _con[child]);//交换parent = child;child = parent * 2 + 1;}else{break;//否则,结束掉}}
}
void pop()
{swap(_con.front(), _con.back());_con.pop_back();adjust_down(0);
}
迭代器区间构造
这里其实注意的就一点,当把数据给到适配器的容器后,要保证是堆结构!所以就要建堆,建堆的方式有两种(详见数据结构那里)向上调整建堆 和 向下调整建堆!
template<class Iterator>
priority_queue(Iterator first, Iterator last):_con(first, last)
{int sz = _con.size();//向下调整建堆 O(N)for (int i = (sz - 1) / 2; i >= 0; i--){adjust_down(i);}//向下调整建堆 O(N*logN)//for (int i = 1; i < sz; i++)//{// adjust_up(i);//}
}
全部源码
#pragma once#include <vector>namespace cp
{template<class T>struct less{bool operator()(const T& a, const T& b){return a < b;}};template<class T>struct greater{bool operator()(const T& a, const T& b){return a > b;}};template<class T, class Con = std::vector<T>, class cmp = less<T>>class priority_queue{public:priority_queue() {}template<class Iterator>priority_queue(Iterator first, Iterator last):_con(first, last){int sz = _con.size();//向下调整建堆 O(N)for (int i = (sz - 1) / 2; i >= 0; i--){adjust_down(i);}//向下调整建堆 O(N*logN)//for (int i = 1; i < sz; i++)//{// adjust_up(i);//}}bool empty() const{return _con.empty();}size_t size() const{return _con.size();}const T& top() const {return _con.front();}void push(const T& val){_con.push_back(val);adjust_up(_con.size() - 1);}void pop(){swap(_con.front(), _con.back());_con.pop_back();adjust_down(0);}private:void adjust_up(size_t child){size_t parent = (child - 1) / 2;while (child > 0){if (cmp()(_con[parent], _con[child]))//孩子比父亲大(小),交换{swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;//否则,结束掉}}}void adjust_down(size_t parent){size_t child = parent * 2 + 1;//假设第一个孩子就是要交换的孩子while (child < _con.size()){if (child + 1 < _con.size() && cmp()(_con[child], _con[child + 1]))//假设错了{++child;//调整}if (cmp()(_con[parent], _con[child]))//孩子比父亲大(小){swap(_con[parent], _con[child]);//交换parent = child;child = parent * 2 + 1;}else{break;//否则,结束掉}}}private:Con _con;};
}
OK,验证一下:
OK,没有问题!本期内容就分享到这里,好兄弟我们下期再见!
结束语:无人问津的日子,更应该加倍努力!
相关文章:

priority_queue的使用以及模拟实现
前言 上一期我们对stack和queue进行了使用的介绍,以及对底层的模拟实现!以及容器适配器做了介绍,本期我们在来介绍一个容器适配器priority_queue! 本期内容介绍 priority_queue的使用 仿函数介绍 priority_queue的模拟实现 什么…...

主机有被植入挖矿病毒篡改系统库文件
查看主机有被植入挖矿病毒篡改系统库文件的行为 排查方法 挖矿病毒被植入主机后,利用主机的运算力进行挖矿,主要体现在CPU使用率高达90%以上,有大量对外进行网络连接的日志记录。 Linux主机中挖矿病毒后的现象如下图所示: &…...
Python 推导式介绍
Python推导式是一种简洁而强大的语法,用于在一行代码中创建集合(list、set、dictionary)的方式。推导式使得代码更加简洁易读,提高了代码的可读性和可维护性。Python中有列表推导式、集合推导式和字典推导式三种类型。 列表推导式…...

VUE3和SpringBoot实现ChatGPT页面打字效果SSE流式数据展示
在做这个功能之前,本人也是走了很多弯路(花了好几天才搞好),你能看到本篇博文,那你就是找对地方了。百度上很多都是使用SseEmitter这种方式,这种方式使用的是websocket,使用这种方式就搞复杂了&…...
ClickHouse入门篇:一文带你学习ClickHouse
ClickHouse 是一个用于联机分析处理(OLAP)的列式数据库管理系统(DBMS)。由于其独特的数据存储和处理架构,ClickHouse 能够提供高速数据插入和实时查询性能。下面是对 ClickHouse 的详细介绍,包括其特性、应用场景和架构: 特性 列式存储: 数…...

基于小程序实现的校园失物招领系统
作者主页:Java码库 主营内容:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】:Java 【框架】:spring…...

损失函数篇 | YOLOv8更换损失函数之Powerful-IoU(2024年最新IoU)
前言:Hello大家好,我是小哥谈。损失函数是机器学习中用来衡量模型预测值与真实值之间差异的函数。在训练模型时,我们希望通过不断调整模型参数,使得损失函数的值最小化,从而使得模型的预测值更加接近真实值。不同的损失函数适用于不同的问题,例如均方误差损失函数适用于回…...

(学习日记)2024.04.11:UCOSIII第三十九节:软件定时器
写在前面: 由于时间的不足与学习的碎片化,写博客变得有些奢侈。 但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。 既然如此 不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录&a…...
wordpress全站开发指南-面向开发者及深度用户(全中文实操)--wordpress是什么
WordPress简介 WordPress是一个开源的内容管理系统(CMS),广泛用于创建和管理网站。它最初是作为一个博客平台开始的,但现在已经发展成为一个功能强大的网站建设工具,可以用于创建各种类型的网站,包括个人博…...

瑞_23种设计模式_访问者模式
文章目录 1 访问者模式(Visitor Pattern)1.1 介绍1.2 概述1.3 访问者模式的结构1.4 访问者模式的优缺点1.5 访问者模式的使用场景 2 案例一2.1 需求2.2 代码实现 3 案例二3.1 需求3.2 代码实现 4 拓展——双分派4.1 分派4.2 动态分派(多态&am…...
Docker网络代理配置 可能埋下的坑
Docker 网络代理配置 1. 在 /etc/systemd/system 目录下创建 docker.service.d 目录 sudo mkdir -p /etc/systemd/system/docker.service.d2. 在/etc/systemd/system/docker.service.d下创建 http-proxy.conf 文件 sudo touch /etc/systemd/system/docker.service.d/http-pr…...

外包干了3天,技术退步明显.......
先说一下自己的情况,大专生,19年通过校招进入杭州某软件公司,干了接近4年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…...

分布式向量数据库-安装部署
下载 GitHub - pgvector/pgvector: Open-source vector similarity search for Postgres 源码编译 ##文件解压缩 unzip pgvector-0.6.2.zip ##编译 make && make install 功能验证 #安装扩展CREATE EXTENSION vector;#创建测试表CREATE TABLE items (id bigseri…...

【深入理解计算机系统第3版】有符号数和无符号数转换以及移位运算练习题2.23
题目 考虑下面的C函数: int fun1(unsigned word) {return (int) ((word << 24) >> 24); }int fun2(unsigned word) {return ((int) word << 24) >> 24; } 假设一个采用补码运算的机器上以32位程序来执行这些函数。还假设有符号数值的右移…...

Linux函数学习 epoll
1、Linux epoll函数 1.1、创建epoll实例 int epoll_create1(int flag); 返回值:-1 失败,非负数 成功 flag :默认传入0 1.2、管理epoll对象 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); epfd :e…...

2024年4月12日 十二生肖 今日运势
小运播报:2024年4月12日,星期五,农历三月初四 (甲辰年戊辰月丙午日),法定工作日。 红榜生肖:羊、狗、虎 需要注意:牛、马、鼠 喜神方位:西南方 财神方位:…...

代码随想录第36、37天| 435. 无重叠区间 763.划分字母区间 56. 合并区间
435. 无重叠区间 435. 无重叠区间 - 力扣(LeetCode) 代码随想录 (programmercarl.com) 贪心算法,依然是判断重叠区间 | LeetCode:435.无重叠区间_哔哩哔哩_bilibili 给定一个区间的集合 intervals ,其中 intervals[…...

代码学习记录40---动态规划
随想录日记part40 t i m e : time: time: 2024.04.10 主要内容:今天开始要学习动态规划的相关知识了,今天的内容主要涉及: 买卖股票的最佳时机加强版。 123.买卖股票的最佳时机III 188.买卖股票的最佳时机…...

java八股——消息队列MQ
上一篇传送门:点我 目前只学习了RabbitMQ,后续学习了其他MQ后会继续补充。 MQ有了解过吗?说说什么是MQ? MQ是Message Queue的缩写,也就是消息队列的意思。它是一种应用程序对应用程序的通信方法,使得应用…...

【前端Vue】Vue3+Pinia小兔鲜电商项目第5篇:整体认识和路由配置,本资源由 收集整理【附代码文档】
Vue3ElementPlusPinia开发小兔鲜电商项目完整教程(附代码资料)主要内容讲述:认识Vue3,使用create-vue搭建Vue3项目1. Vue3组合式API体验,2. Vue3更多的优势,1. 认识create-vue,2. 使用create-vue创建项目,1. setup选项的写法和执行…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...

css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
css3笔记 (1) 自用
outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size:0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格ÿ…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...