当前位置: 首页 > news >正文

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进行了使用的介绍&#xff0c;以及对底层的模拟实现&#xff01;以及容器适配器做了介绍&#xff0c;本期我们在来介绍一个容器适配器priority_queue&#xff01; 本期内容介绍 priority_queue的使用 仿函数介绍 priority_queue的模拟实现 什么…...

主机有被植入挖矿病毒篡改系统库文件

查看主机有被植入挖矿病毒篡改系统库文件的行为 排查方法 挖矿病毒被植入主机后&#xff0c;利用主机的运算力进行挖矿&#xff0c;主要体现在CPU使用率高达90%以上&#xff0c;有大量对外进行网络连接的日志记录。 Linux主机中挖矿病毒后的现象如下图所示&#xff1a; &…...

Python 推导式介绍

Python推导式是一种简洁而强大的语法&#xff0c;用于在一行代码中创建集合&#xff08;list、set、dictionary&#xff09;的方式。推导式使得代码更加简洁易读&#xff0c;提高了代码的可读性和可维护性。Python中有列表推导式、集合推导式和字典推导式三种类型。 列表推导式…...

VUE3和SpringBoot实现ChatGPT页面打字效果SSE流式数据展示

在做这个功能之前&#xff0c;本人也是走了很多弯路&#xff08;花了好几天才搞好&#xff09;&#xff0c;你能看到本篇博文&#xff0c;那你就是找对地方了。百度上很多都是使用SseEmitter这种方式&#xff0c;这种方式使用的是websocket&#xff0c;使用这种方式就搞复杂了&…...

ClickHouse入门篇:一文带你学习ClickHouse

ClickHouse 是一个用于联机分析处理(OLAP)的列式数据库管理系统(DBMS)。由于其独特的数据存储和处理架构&#xff0c;ClickHouse 能够提供高速数据插入和实时查询性能。下面是对 ClickHouse 的详细介绍&#xff0c;包括其特性、应用场景和架构&#xff1a; 特性 列式存储: 数…...

基于小程序实现的校园失物招领系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…...

损失函数篇 | YOLOv8更换损失函数之Powerful-IoU(2024年最新IoU)

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

(学习日记)2024.04.11:UCOSIII第三十九节:软件定时器

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…...

wordpress全站开发指南-面向开发者及深度用户(全中文实操)--wordpress是什么

WordPress简介 WordPress是一个开源的内容管理系统&#xff08;CMS&#xff09;&#xff0c;广泛用于创建和管理网站。它最初是作为一个博客平台开始的&#xff0c;但现在已经发展成为一个功能强大的网站建设工具&#xff0c;可以用于创建各种类型的网站&#xff0c;包括个人博…...

瑞_23种设计模式_访问者模式

文章目录 1 访问者模式&#xff08;Visitor Pattern&#xff09;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 动态分派&#xff08;多态&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天,技术退步明显.......

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

分布式向量数据库-安装部署

下载 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函数&#xff1a; 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); 返回值&#xff1a;-1 失败&#xff0c;非负数 成功 flag &#xff1a;默认传入0 1.2、管理epoll对象 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); epfd &#xff1a;e…...

2024年4月12日 十二生肖 今日运势

小运播报&#xff1a;2024年4月12日&#xff0c;星期五&#xff0c;农历三月初四 &#xff08;甲辰年戊辰月丙午日&#xff09;&#xff0c;法定工作日。 红榜生肖&#xff1a;羊、狗、虎 需要注意&#xff1a;牛、马、鼠 喜神方位&#xff1a;西南方 财神方位&#xff1a;…...

代码随想录第36、37天| 435. 无重叠区间 763.划分字母区间 56. 合并区间

435. 无重叠区间 435. 无重叠区间 - 力扣&#xff08;LeetCode&#xff09; 代码随想录 (programmercarl.com) 贪心算法&#xff0c;依然是判断重叠区间 | LeetCode&#xff1a;435.无重叠区间_哔哩哔哩_bilibili 给定一个区间的集合 intervals &#xff0c;其中 intervals[…...

代码学习记录40---动态规划

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

java八股——消息队列MQ

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

【前端Vue】Vue3+Pinia小兔鲜电商项目第5篇:整体认识和路由配置,本资源由 收集整理【附代码文档】

Vue3ElementPlusPinia开发小兔鲜电商项目完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;认识Vue3&#xff0c;使用create-vue搭建Vue3项目1. Vue3组合式API体验,2. Vue3更多的优势,1. 认识create-vue,2. 使用create-vue创建项目,1. setup选项的写法和执行…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用

一、方案背景​ 在现代生产与生活场景中&#xff0c;如工厂高危作业区、医院手术室、公共场景等&#xff0c;人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式&#xff0c;存在效率低、覆盖面不足、判断主观性强等问题&#xff0c;难以满足对人员打手机行为精…...