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选项的写法和执行…...

前端项目部署教程——有域名无证书
一、拉取nginx镜像 docker pull nginx //先拉取nginx镜像二、打包前端项目 1、将Vue打包项目传输到/usr/local/vue/下blog和admin文件夹下 2、在/usr/local/nginx下创建nginx.conf文件,格式如下: events {worker_connections 1024; }http {include …...

后端项目部署教程
一、打包jar包 lyamanoblog-server-0.0.1.jar ps:运行时可能会提醒不能有大写字母,所以用的都是小写字母 二、编写Dockerfile文件 FROM java:8 VOLUME /tmp ADD lyamanoblog-server-0.0.1.jarblog.jar ENTRYPOINT ["java","-Djava.securit…...

【微命令】git 如何修改某个分支的名字(git branch -m newbranch)
简要信息,快速记录 命令 # 切换到某个需要修改的分支 git checkout oldbranch# 修改分支名字 git branch -m newbranch假设作为git设计者,要用来修改branch的命令,那么就是 git branch作为前缀,然后进一步修改的命令是branch相关…...

Unity UI 优化技巧
将画布分割为多个 问题:当 UI Canvas 的任何元素发生变化时,都会影响整个 Canvas。 Canvas 是 Unity UI 的重要组成部分。它创建一个网格来表示放置在其顶部的 UI 元素,在 UI 元素更改时重建网格,并调用 GPU 来渲染实际的用户界面。 创建这些网络可能非常昂贵。UI 元素应…...

前端学习之DOM编程案例:抽奖案例
代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>抽奖案例</title><style>*{margin: 0;padding: 0;}</style> </head> <body><div id"container"&g…...

解决windows下Qt Creator显示界面过大的问题
🐌博主主页:🐌倔强的大蜗牛🐌 📚专栏分类:QT❤️感谢大家点赞👍收藏⭐评论✍️ 目录 问题描述 解决方法 1、右击此电脑--->属性 2、点击高级系统设置--->点击环境变量 3、 找到系…...

MySQL 通信协议 tcp c/s架构 jdbc java
简介 服务器启动后,会使用 TCP 监听一个本地端口,当客户端的连接请求到达时,就会执行三段握手以及 MySQL 的权限验证;验证成功后,客户端开始发送请求,服务器会以响应的报文格式返回数据;当客户…...

蓝桥杯第十三届电子类单片机组决赛程序设计
前言 一、决赛题目 1.比赛题目 2.题目解读 二、功能实现 1.关于定时器资源 1)超声波和NE555需要的定时器资源 2)定时器2 2.单位切换 3.数据长度不足时,高位熄灭 4.AD/DA多通道的处理 5.PWM输出 6.长按功能的实现 三、完整代码演…...

【Entity Framework】如何使用EF中的生成值
【Entity Framework】如何使用EF中的生成值 文章目录 【Entity Framework】如何使用EF中的生成值一、概述二、默认值三、计算列四、设置主键五、显示配置值生成六、设置日期/时间值生成6.1 创建时间戳6.2 更新时间戳 七、替代值生成八、无值生成九、总结 一、概述 数据库列的值…...

【MATLAB源码-第185期】基于matlab的16QAM系统相位偏移估计EOS算法仿真,对比补偿前后的星座图误码率。
操作环境: MATLAB 2022a 1、算法描述 1. 引言 M-QAM调制技术的重要性 现代通信系统追求的是更高的数据传输速率和更有效的频谱利用率。M-QAM调制技术,作为一种高效的调制方案,能够通过在相同的带宽条件下传输更多的数据位来满足这一需求…...