c++:优先级队列(priority queue)使用及底层详解,附带仿函数初步使用

文章目录

  • 优先级队列的使用
    • 大堆
    • 小堆
      • **注意**
  • 优先级队列的模拟实现
    • push
    • pop
    • size
    • empty
    • top
  • 仿函数
    • 仿函数是什么
    • push
    • pop
  • 仿函数结合优先级队列的优势


优先级队列的使用

优先级队列本质是就是完全二叉树,是个堆.我们可以用优先级队列来取出一段序列中的前N个最大值.

在这里插入图片描述

	priority_queue<int> pq;

第一个模板参数是数据类型,第二个是容器适配器,通俗点来讲就是这个堆用什么容器来实现,第三个就是排序方式(用仿函数来实现),这个能决定这个堆是大堆还是小堆.

大堆

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int main()
{priority_queue<int> pq;pq.push(1);pq.push(100);pq.push(66);pq.push(9);pq.push(20);pq.push(2);pq.push(8);while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;return 0;
}

在这里插入图片描述

将一些无序的数据存到优先级队列里面,它会给数据排成一个堆,我们可以依次取出数据,然后删除.
默认是大堆

小堆

	priority_queue<int, vector<int>, greater<int>> pq;	

只需要在定义时声明就行.
在这里插入图片描述

注意

greater是小堆,less是大堆

优先级队列的模拟实现

这里我们先实现一个大堆

	template<class T, class Container = vector<T>>class priority_queue{private:Container _con;}

因为二叉树push数据的时候经常要交换位置,我们经常要访问它的父亲节点和子节点,所以默认的容器适配器是vector,你也可以改成deque(双向队列)

push

		void push(const T& val){_con.push_back(val);adjust_up(_con.size() - 1);}

堆的插入是尾插,然后再把这个数据向上调整

	void adjust_up(size_t child){size_t parent = (child - 1) / 2;while (child > 0){if(_con[child] > _con[parent]){swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}

比较逻辑:找到父亲节点,将父亲节点和子节点比较,如果子节点>父亲节点,交换,然后更新节点.
注意:父亲节点=(子节点-1)/2

pop

		void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjust_down(0);}

在删除节点的时候,为了效率.我们把第一个节点和最后一个节点交换,删除最后一个节点(此时堆的最大值).再把第一个节点(原来的最后一个节点)向下调整.

	void adjust_down(size_t parent){size_t child = parent * 2 + 1;if (child + 1 < _con.size() && _con[child] < _con[child + 1])child++;while (child < _con.size()){if (_con[parent]<_con[child]){swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}

向下调整的过程中,如果满足父亲节点<子节点,二者交换.直到父亲节点>子节点或者子节点越界.
注意在向下调整的过程中始终选择大的孩子进行比较,这是为了满足大堆的性质,父亲节点一定>=子节点.
左孩子=父亲节点2+1,右孩子=父亲节点2+2

size

		size_t size(){return _con.size();}

size和empty都可以复用vector里面的函数,但是我们要在前面包上vector的头文件

empty

		bool empty(){return _con.empty();}

top

		const T& top(){return _con[0];}

堆的头就是数组里面的第一个数据

仿函数

我们如果要改变大小堆的话,其实只需要把小于改成大于,大于改成小于就行.但如果每次都这么改,会大大增加我们的工作量,在c语言中,我们可以使用函数指针来解决.在c++中,祖师爷设计了一种更方便的做法,也就是仿函数.

仿函数是什么

仿函数本质上是一个类,这个类能模拟函数的行为.实现内置类型或者自定义类型的比较

template<class T>
struct Less
{bool operator()(const T& x, const T& y){return x < y;}
};
int main()
{Less<int> func;cout << func(1, 2) << endl;cout << func.operator()(1, 2) << endl;return 0;
}

在这里插入图片描述

func(1,2)看起来是不是跟我们平时调用函数一样,传两个参数.实际上,Less仿函数里对()进行操作符重载,让我们可以比较两个数的大小

这个做法衍生到堆上面,我们可以传两个仿函数,一个大于,一个小于.然后在堆里面实例化出对象.

	template<class T>struct greater{bool operator()(const T& t1,const T& t2){return t1 > t2;}};template<class T>struct less{bool operator()(const T& t1, const T& t2){return t1 < t2;}};

push

void adjust_up(size_t child)
{Compare com;size_t parent = (child - 1) / 2;while (child > 0){//if(_con[child] > _con[parent])//if(_con[parent] < _con[child])if (com(_con[parent], _con[child])){swap(_con[child], _con[parent]);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){Compare com;size_t child = parent * 2 + 1;if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))child++;while (child < _con.size()){//if (_con[parent] < _con[sun])if (com(_con[parent], _con[child])){swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}else{break;}}}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjust_down(0);}

仿函数结合优先级队列的优势

priority_queue<int> pq;
priority_queue<int,vector<int>,greater<int>> pq;

首先我们可以自己控制大堆/小堆.
其次在面对商品等复杂类型中,需要我们根据价格,评价,销量等等进行排序时.单靠商品类里面的一个操作符重载小于或者大于是不够的,我们可以写多个仿函数,争对价格,评价等进行比较.

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

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

相关文章

Postman的一些使用技巧

Postman 是一个流行的 API 开发工具&#xff0c;用于设计、开发、测试、发布和监控 API。在现代web开发中使用非常广泛。后端开发必备而且必会的工具。 目录 1.配置环境变量 2.动态变量 3.脚本 4.测试 5.模拟 6.监控 7.集合运行器 8.响应保存 9.请求历史 10.同步请求…

嵌入式Linux编辑器vi

一、vi是什么 vi是Linux系统的第一个全屏幕交互式编辑工具。 vi与vim vi 和 vim 是 Linux 和 Unix 系统上非常流行的文本编辑器。尽管 vi 是最初的版本&#xff0c;但 vim&#xff08;Vi IMproved&#xff09;是它的一个增强版本&#xff0c;提供了更多的功能和易用性。 vi 是一…

使用ESP8266连接EMQX完成数据上传

国庆期间在家里窝着哪里也没去&#xff0c;到处都是人。打算自己捣鼓点小玩意&#xff0c;相信大家对STM32ESP8266ONENET这种组合已经见怪不怪了&#xff0c;这次不走寻常路&#xff0c;咱们搞点不一样的。正巧自己也一直有做一套网关系统的想法&#xff0c;因此就有了下面这篇…

【论文阅读笔记】关于“二进制函数相似性检测”的调研(Security 22)

个人博客链接 注&#xff1a;部分内容参考自GPT生成的内容 [Security 22] 关于”二进制函数相似性检测“的调研&#xff08;个人阅读笔记&#xff09; 论文&#xff1a;《How Machine Learning Is Solving the Binary Function Similarity Problem》&#xff08;Usenix Securi…

算法提高之背包问题背包问题求具体方案

算法提高之背包问题背包问题求具体方案 核心思想&#xff1a;01背包 dp输出方案 因为求字典序最小的方案 所以当取第i个物品时 下一步要求的就是i1 ~ n的最大方案 所以f意义改变 变成了第i个元素到最后一个元素总容量为j的最优解 之前是前i个物品总容量为j的最优解 这样在之…

[AIGC] MVCC 是怎么实现的

InnoDB 实现的MVCC&#xff0c;是通过 ReadView Undo Log 实现的&#xff0c;Undo Log 保存了历史快照&#xff0c;ReadView可见性规则帮助判断当前版本的数据是否可见。 具体操作时&#xff1a; SELECT InnoDB会根据以下两个条件检查每行记录&#xff1a; a. InnoDB只查找版本…

leetCode71. 简化路径

leetCode71. 简化路径 代码 // 化简&#xff1a;就是把所有的., .. // 去掉弄成进入想进的目录&#xff0c;且结果最后不能有/ // 实现思路&#xff1a; 本质上是一个栈&#xff0c;就是进栈出栈的一个模拟实现 class Solution { public:string simplifyPath(string path) {//…

面试算法-链表-反转链表(golang、c++)

目录 1、题目 2、解题思路 2.1 遍历、迭代 2.2 递归 3、源代码 3.1 c 3.2 golang 4、复杂度分析 4.1 遍历、迭代法 4.2 迭代法 1、题目 链表是一种常用的数据结构&#xff0c;链表的特点是插入、删除节点的效率非常高&#xff0c;因为他不需要移动其他任何元素&…

Linux——守护进程化(独立于用户会话的进程)

目录 前言 一、进程组ID与会话ID 二、setsid() 创建新会话 三、daemon 守护进程 前言 在之前&#xff0c;我们学习过socket编程中的udp通信与tcp通信&#xff0c;但是当时我们服务器启动的时候&#xff0c;都是以前台进程的方式启动的&#xff0c;这样很不优雅&#xff0c…

数据分析:基于DESeq2的转录组功能富集分析

介绍 DESeq2常用于识别差异基因&#xff0c;它主要使用了标准化因子标准化数据&#xff0c;再根据广义线性模型判别组间差异&#xff08;组间残差是否显著判断&#xff09;。在获取差异基因结果后&#xff0c;我们可以进行下一步的富集分析&#xff0c;常用方法有基于在线网站…

银行智能化数据安全分类分级实践分享

文章目录 前言一、数据安全智能分类分级平台建设背景二、数据安全分类分级建设思路和实践1、做标签– 数据安全标签体系2、打标签– 鹰眼智能打标平台 3.03、用标签– 全行统一“数据安全打标签结果”服务提供前言 随着国家对数据安全的高度重视,以及相关法律法规的出台,数据…

python数据分析中数据可视化简单入门

1.折线图表 首先引入相关包pyecharts&#xff0c;如果没下载可以先下载 pip install pyecharts from pyecharts.charts import Lineline Line() # 添加x轴 line.add_xaxis([呱了个呱,羊村,牟多,蜂地,喵帕斯]) # 添加y轴 line.add_yaxis("GDP",[50,30,40,34,63,22])…

01 JVM --

JVM (Java Virtual Machine) 是一个虚拟机HotSpot 是 JVM 概念的一个实现。HotSpot 虚拟机通过即时编译 (JIT) 技术将 Java 字节码转换为本地机器码&#xff0c;以提高程序的执行效率。OpenJDK 是一个项目名&#xff0c;它在 HotSpot 的基础上开发了 HotSpot 的开源实现方法区是…

Redhat Linux忘记密码解决方案

1、重启系统 2、将光标移动到要启动的内核 3、按e编辑当前条目 4、将光标移动以Linux开头的行&#xff0c;此为内核命令行 5、在末尾添加人的rd.break 6、按ctrlx继续启动&#xff0c;如果发现输入的rd.break不能进入到伪系统&#xff0c;那么改为 rd.break consoletty0 (按ctr…

设计模式-03 设计模式-工厂模式factory-内部工厂

设计模式-03 设计模式-工厂模式factory-内部工厂 目录 设计模式-03 设计模式-工厂模式factory-内部工厂 1.定义 2.内涵 3.案例对比 4.特点 4.总结 1.定义 内部工厂模式是一种创建类对象的方式&#xff0c;其中工厂方法被封装在类内部&#xff0c;客户端只能通过类的公共…

epoll的LT和ET模式介绍

目录 1.epoll的LT和ET模式介绍 2.epoll的ET模式如何处理 2.1 epoll的ET模式编程读取数据的处理方式 2.2 将描述符设置为非阻塞模式的方法 3.ET模式的总结 4.epoll的LT模式和ET模式总结 5.IO复用总结 1.epoll的LT和ET模式介绍 epoll对文件描述符有两种操作模式: LT(Leve…

Linux(openEuler、CentOS8)常用的IP修改方式(文本配置工具nmtui+配置文件+nmcli命令)

----本实验环境为openEuler系统<以server方式安装>&#xff08;CentOS类似&#xff0c;可参考本文&#xff09;---- 一、知识点 &#xff08;一&#xff09;文本配置工具nmtui(openEuler已预装) nmtui&#xff08;NetworkManager Text User Interface&#xff09;是一…

关于apache+php用户验证

一.直接在apache配置配置用户信息 1.apache配置可以参考外部文档 https://developer.aliyun.com/article/507049 2.上面配置好在php获取用户信息&#xff08;登录apache会拦截&#xff09; $userName $_SERVER[PHP_AUTH_USER];$password $_SERVER[PHP_AUTH_PW]; 二.上面直…

在线OJ——链表经典例题详解

引言&#xff1a;本篇博客详细讲解了关于链表的三个经典例题&#xff0c;分别是&#xff1a;环形链表&#xff08;简单&#xff09;&#xff0c;环形链表Ⅱ&#xff08;中等&#xff09;&#xff0c;随机链表的复制&#xff08;中等&#xff09;。当你能毫无压力地听懂和成功地…

再学Java基础——final关键字

在Java中&#xff0c;final关键字是一个修饰符&#xff0c;它可以应用于类、方法、变量和常量。以下是final关键字在Java中的不同用途及其作用&#xff1a; final类&#xff1a; 当一个类被声明为final时&#xff0c;它不能被继承。这意味着没有其他类可以扩展这个类。作用&…