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 once

namespace 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;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

科普文之五分钟轻松入门Generative AI

1. 引言 最近&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;在行业内带来了巨大的变动。还记得 2022 年 11 月推出的 ChatGPT 吗&#xff1f;在短时间内&#xff0c;它就成为了有史以来用户数量最快突破 1 亿的产品。 人工智能已经存在了很长一段时间&…

二叉树算法

递归序 每个节点都能回到3次! 相当于2执行完然后返回了代码会往下走,来到3节点 小总结: 也就是4节点先来到自己一次,不会执行if,先调用自己左边的那个函数,但是是null,直接返回。 这个函数执行完了,就会回到自己,调用自己右边的那个函数,结果又是空,又返回,回到…

Hive SQL必刷练习题:连续问题 间断连续(*****)

问题描述&#xff1a; 1&#xff09; 连续问题&#xff1a;找出连续三天&#xff08;或者连续几天的啥啥啥&#xff09;。 2&#xff09; 间断连续&#xff1a;统计各用户连续登录最长天数&#xff0c;间断一天也算连续&#xff0c;比如1、3、4、6也算登陆了6天 问题分析&am…

Kotlin进阶之协程从上车到起飞

公众号「稀有猿诉」 原文链接 Kotlin进阶之协程从上车到起飞 通过前面的一篇文章我们理解了协程的基本概念&#xff0c;学会协程的基本使用方法&#xff0c;算是正式入门了&#xff0c;接下来就是要深入的学习技术细节和高级使用方法&#xff0c;以期完全掌握Kotlin协程…

等保测评的知识

结合自己所学的知识和网络上的一些知识做个小总结。 目录 一、概念&#xff1a; 二、等级划分&#xff1a; 三、技术要求&#xff1a; 四、管理要求&#xff1a; 五、等保测评实施过程&#xff1a; 六、典型的网络架构&#xff1a; 一、概念&#xff1a; 全称为信息安全等级保…

HarmonyOS NEXT应用开发之Web获取相机拍照图片案例

介绍 本示例介绍如何在HTML页面中拉起原生相机进行拍照&#xff0c;并获取返回的图片。 效果预览图 使用说明 点击HTML页面中的选择文件按钮&#xff0c;拉起原生相机进行拍照。完成拍照后&#xff0c;将图片在HTML的img标签中显示。 实现思路 添加Web组件&#xff0c;设置…

mysql索引(聚簇索引,非聚簇索引:回表)( innodb 引擎库表设计注意事项)

索引文件存放位置 MyISAM 引擎每个表 都会有3个文件&#xff1a;表结构 &#xff08;.frm&#xff09; 表数据 &#xff08; .MYD&#xff09; 索引 &#xff08;.MYI&#xff09; InnoDB 引擎每个表 都会有2个文件&#xff1a;表结构 &#xff08;.frm&#xff09;表数据索引…

flex 布局实现局部 区域滚动

需求描述&#xff1a; 头部固定不动&#xff0c;内容部分区域滚动 一、实现代码 1、实现逻辑 1. 最外层父元素&#xff0c;必须要flex布局&#xff0c;并且宽度、高度撑满可视化区域 >代码为 width: 100vw;height: 100vh; 2. 只给滚动区域设置 flex:1; overflow: scroll…

定义一个符号常量,并计算

这段代码的输出结果是什么 #include <stdio.h> #define PI 32 int main() { int iPI*2; printf("i%d\n",i);} 是7。 我问了一下AI&#xff0c;AI也回答错了&#xff0c;这是个值得注意的地方。

Error response from daemon Get server gave HTTP response to HTTPS client

使用docker compose拉起docker镜像时&#xff0c;若出现如下报错 Error response from daemon: Get "https://devops.test.cn:5000/v2/": http: server gave HTTP response to HTTPS client表示Docker守护进程无法从指定url获取响应&#xff0c; 可能原因有以下&…

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

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

29.网络游戏逆向分析与漏洞攻防-网络通信数据包分析工具-数据推测功能的算法实现

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果 内容参考于&#xff1a;易道云信息技术研究院VIP课 上一个内容&#xff1a;28.数据推测结果…

数目之差

解法一&#xff1a; 显然只需让多的在限度内最多即可 #include<iostream> #include<algorithm> using namespace std; #define endl \n void solve() {int n, k, num0 0, num1 0;cin >> n >> k;string s;cin >> s;for (int i 0; i < s.s…

配置OGG 如何批量修改源端及目标端序列值_满足客户变态需求学会这招你就赚了

欢迎您关注我的公众号【尚雷的驿站】 **************************************************************************** 公众号&#xff1a;尚雷的驿站 CSDN &#xff1a;https://blog.csdn.net/shlei5580 墨天轮&#xff1a;https://www.modb.pro/u/2436 PGFans&#xff1a;ht…

YOLOv9改进策略:注意力机制 | 用于微小目标检测的上下文增强和特征细化网络ContextAggregation,助力小目标检测,暴力涨点

&#x1f4a1;&#x1f4a1;&#x1f4a1;本文改进内容&#xff1a;用于微小目标检测的上下文增强和特征细化网络ContextAggregation&#xff0c;助力小目标检测 yolov9-c-ContextAggregation summary: 971 layers, 51002153 parameters, 51002121 gradients, 238.9 GFLOPs 改…

LeetCode讲解算法1-排序算法(Python版)

文章目录 一、引言问题提出 二、排序算法1.选择排序&#xff08;Selection Sort&#xff09;2.冒泡排序3.插入排序&#xff08;Insertion Sort&#xff09;4.希尔排序&#xff08;Shell Sort&#xff09;5.归并排序&#xff08;Merge Sort&#xff09;6.快速排序&#xff08;Qu…

掘根宝典之C++RTTI和类型转换运算符

什么是RTTI RTTI是运行阶段类型识别的简称。 哪些是RTTI? C有3个支持RTTI的元素。 1.dynamic_cast运算符将使用一个指向基类的指针来生成一个指向派生类的指针&#xff0c;否则该运算符返回0——空指针。 2.typeid运算符返回一个指出对象类型的信息 3.type_info结构存储…

图解Transformer——注意力计算原理

文章目录 1、输入序列怎样传入注意力模块 2、进入注意力模块的矩阵的每一行&#xff0c;都是源序列中的一个词 3、每一行&#xff0c;都会经过一系列可学习的变换操作 4、如何得到注意力分数 5、Query、Key、Value的作用 6、点积&#xff1a;衡量向量之间的相似度 7、Transform…

【趣味项目】命令行图片格式转换器

【趣味项目】一键生成LICENSE 项目地址&#xff1a;GitHub 项目介绍 一款命令行内可以批量修改图片格式的工具 使用方式 npm install xxhls/image-transformer -gimg-t --name.*.tiff --targetpng --path./images --recursiontrue技术选型 typeScript: 支持类型体操chal…

图论题目集一(代码 注解)

目录 题目一&#xff1a; 题目二&#xff1a; 题目三&#xff1a; 题目四&#xff1a; 题目五&#xff1a; 题目六&#xff1a; 题目七&#xff1a; 题目一&#xff1a; #include<iostream> #include<queue> #include<cstring> using namespace st…