优先队列 priority_queue详解
说到,priority_queue优先队列。必须先要了解啥是堆与运算符重载(我在下方有解释)。
否则只知皮毛,极易忘记==寸步难行。
但在开头,还是简单的说下怎么用
首先,你需要调用
#include <queue>
在main函数中,声明格式为:priority_queue<结构类型> 队列名;
priority_queue <int> i;
priority_queue <double> d;
常用操作
priority_queue<int> p;
p.size(); // 获取长度
p.empty(); // 是否为空
p.push(val); // 插入
p.pop(); // 删除首个元素
p.top(); // 获取头部元素
以下是完整应用:
priority_queue隶属于<queue>
而queue又是容器适配器。
故,priority_queue也是容器适配器
容器适配器 代表这个函数底层,是可插拔的,能用(vector、deque实现)。
但要注意list不能作为底层容器,因为list不支持随机访问 (如operator[])
简而言之,priority_queue就像汽车,而内部的发动机,有原装的。如果你不满意,也可以换成其他!
priority_queue<int,vector<int>,cmp> pq;vector<int>就是其底层默认的容器,cmp是重载过后的(结构体or类)
初识:
#include <iostream>
#include <queue>
using namespace std;
struct cmp{bool operator()(int a,int b){return a<b; // 因为是正常比较,固为最大堆// return a>b 最小堆}
};
int main(){priority_queue<int,vector<int>,cmp> pq; pq.push(3);pq.push(2);pq.push(1);while(pq.size()!=0){cout<<pq.top()<<endl;pq.pop();}return 0;
}
我看了很多博客,大多数博主,重载的符号都是<符号,而不是(),咱们就在这里说一说。
重载 operator< 的优点:
-
简单直观:直接在类中定义比较逻辑,适合类本身需要一个固定的排序规则。
-
通用性:不仅适用于
priority_queue,还适用于其他需要比较的场景,如sort函数。
自定义比较函数对象的优点:
-
灵活性:可以在不修改类定义的情况下,为不同的排序需求提供多种比较逻辑。
-
避免全局污染:比较逻辑封装在函数对象中,不会影响类的全局比较行为。
源码中的关键逻辑
在priority_queue的底层实现中,堆调整(如push或pop)时会调用比较器:
// 伪代码:堆的上浮操作
void _upheap(int i) {while (i > 0) {int parent = (i-1)/2;if (Compare()(heap[parent], heap[i])) { // 调用operator()swap(heap[parent], heap[i]);i = parent;} else break;}
}
底层的简单实现:
其实一下代码,就是堆的低配版,只要知道什么是堆排序,就能够轻松解决优先队列。
#include <iostream>
#include <vector>template <typename T>
class PriorityQueue {
private:std::vector<T> heap;// 上浮操作,用于维护堆的性质void siftUp(int index) {while (index > 0) {int parent = (index - 1) / 2;if (heap[parent] >= heap[index]) {break;}std::swap(heap[parent], heap[index]);index = parent;}}// 下沉操作,用于维护堆的性质void siftDown(int index) {int size = heap.size();while (true) {int leftChild = 2 * index + 1;int rightChild = 2 * index + 2;int largest = index;if (leftChild < size && heap[leftChild] > heap[largest]) {largest = leftChild;}if (rightChild < size && heap[rightChild] > heap[largest]) {largest = rightChild;}if (largest == index) {break;}std::swap(heap[index], heap[largest]);index = largest;}}public:// 判断队列是否为空bool empty() const {return heap.empty();}// 获取队列的大小size_t size() const {return heap.size();}// 获取堆顶元素T top() const {if (empty()) {throw std::out_of_range("Priority queue is empty");}return heap[0];}// 插入元素void push(const T& value) {heap.push_back(value);siftUp(heap.size() - 1);}// 删除堆顶元素void pop() {if (empty()) {throw std::out_of_range("Priority queue is empty");}std::swap(heap[0], heap.back());heap.pop_back();siftDown(0);}
};int main() {PriorityQueue<int> pq;pq.push(3);pq.push(1);pq.push(2);std::cout << "Top element: " << pq.top() << std::endl;pq.pop();std::cout << "Top element after pop: " << pq.top() << std::endl;return 0;
}
大纲
一、前 K 个高频元素-(解析)-结合unordered_map复合运用,了解map的最小单位pair
二、滑动窗口最大值-(解析)-pair<int,int>复合运用,滑动窗口实践
三、 游戏 蓝桥真题-(解析)-相当于上两道题结合运用
( •̀ ω •́ )✧点击这里,继续学习其他模块吧!
题目:
一、前 K 个高频元素
给你一个整数数组
nums和一个整数k,请你返回其中出现频率前k高的元素。你可以按 任意顺序 返回答案。示例 1:
输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2]示例 2:
输入: nums = [1], k = 1 输出: [1]提示:
1 <= nums.length <= 105k的取值范围是[1, 数组中不相同的元素的个数]- 题目数据保证答案唯一,换句话说,数组中前
k个高频元素的集合是唯一的
class Solution {struct cmp{bool operator()(pair<int,int> p1, pair<int,int> p2){return p1.second<p2.second; // 正常比较}};
public:vector<int> topKFrequent(vector<int>& nums, int k) {unordered_map<int,int> umap;for(int i : nums){umap[i]++;}priority_queue<pair<int,int>,vector<pair<int,int>>,cmp>pq;for(auto it = umap.begin(); it!=umap.end(); ++it){pq.push(*it);}vector<int> vec;while(k--){vec.push_back(pq.top().first);pq.pop();}return vec;}
};
二、滑动窗口最大值
给你一个整数数组
nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的k个数字。滑动窗口每次只向右移动一位。返回 滑动窗口中的最大值 。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7] 解释: 滑动窗口的位置 最大值 --------------- ----- [1 3 -1] -3 5 3 6 7 31 [3 -1 -3] 5 3 6 7 31 3 [-1 -3 5] 3 6 7 51 3 -1 [-3 5 3] 6 7 51 3 -1 -3 [5 3 6] 7 61 3 -1 -3 5 [3 6 7] 7示例 2:
输入:nums = [1], k = 1 输出:[1]提示:
1 <= nums.length <= 105-104 <= nums[i] <= 1041 <= k <= nums.length
class Solution {struct cmp{bool operator()(const pair<int,int>& p1,const pair<int,int>& p2){return p1.first<p2.first;}};
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {vector<int> vec;priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> p;for(int i=0; i<k; ++i){p.push({nums[i],i});}// 添加第一个滑动窗口的最大值vec.push_back(p.top().first);for(int i=k; i<nums.size(); ++i){p.push({nums[i],i});while(p.top().second<=i-k) p.pop();vec.push_back(p.top().first);}return vec;}
};
三、 游戏 蓝桥真题
问题描述
熊大和熊二在玩游戏。他们将 nn 个正整数 a1,a2,...,ana1,a2,...,an 排成一行,然后各用一个长度为 kk 的框在这个数组中各自随机框选出一段长度为 kk 的连续子序列(随机框选指在合法的 n−k+1n−k+1 个连续子序列中均匀随机)。熊大记录了他框出的 kk 个数中的最大值 PP,熊二记录了他框出的 kk 个数的最小值 QQ,他们突然有个疑问:P−QP−Q 的期望是多少?
2024-11-27 Update:Java 时限调整至 1s
输入描述
输入共 22 行。
第一行为两个正整数 n,kn,k。
第二行为 nn 个由空格隔开的正整数 a1,a2,...,ana1,a2,...,an。
输出描述
输出共 11 行,一个浮点数(请保留两位小数)。
样例输入
3 2 1 2 3样例输出
1.00样例说明
一共有四种情况:
熊大框出 [1,2][1,2],P=2P=2;熊二框出 [1,2][1,2],Q=1Q=1,P−Q=1P−Q=1。
熊大框出 [1,2][1,2],P=2P=2;熊二框出 [2,3][2,3],Q=2Q=2,P−Q=0P−Q=0。
熊大框出 [2,3][2,3],P=3P=3;熊二框出 [1,2][1,2],Q=1Q=1,P−Q=2P−Q=2。
熊大框出 [2,3][2,3],P=3P=3;熊二框出 [2,3][2,3],Q=2Q=2,P−Q=1P−Q=1。
所以 P−QP−Q 的期望为(1+0+2+1)/4=1.00(1+0+2+1)/4=1.00。
评测用例规模
对于 20%20% 的数据,保证 n≤102n≤102。
对于 40%40% 的数据,保证 n≤103n≤103。
对于 100%100% 的数据,保证 n≤105n≤105,0<ai≤1090<ai≤109,0<k≤n0<k≤n。
#include <iostream>
#include <queue>
#define ll long long
using namespace std;
struct max_cmp{bool operator()(const pair<ll,int>& p1,const pair<ll,int>& p2){ // 最大堆return p1.first<p2.first;}
};
struct min_cmp{bool operator()(const pair<ll,int>& p1,const pair<ll,int>& p2){ // 最小堆return p1.first>p2.first;}
};
int main()
{priority_queue<pair<ll,int>,vector<pair<ll,int>>,max_cmp> max_p;priority_queue<pair<ll,int>,vector<pair<ll,int>>,min_cmp> min_p;int n,k;cin>>n>>k;for(int i=0; i<k; ++i){ // 拓展ll cur;cin>>cur;max_p.push({cur,i});min_p.push({cur,i});}int P,Q;P = max_p.top().first;Q = min_p.top().first;ll sum = P-Q;for(int i=k; i<n; ++i){ // 增加while(!max_p.empty()&&max_p.top().second<=i-k) max_p.pop();while(!min_p.empty()&&min_p.top().second<=i-k) min_p.pop();ll cur;cin>>cur;max_p.push({cur,i});min_p.push({cur,i});P = max_p.top().first;Q = min_p.top().first;sum += P-Q;}printf("%.2lf",(double)sum/(n-k+1));return 0;
}
知识点:
重载函数与重载运算符 :: 基础巩固 ::
这里我着重要掌握的是,重载运算符
重载函数
在同一作用域中,可以声明几个功能类似的同名函数。但是形式参数(指参数类型、顺序等)必须不同。如下:
#include <iostream>
using namespace std;\
struct printData{
public:void print(int i){cout<<i<<endl;}void print(double i){cout<<i<<endl;}void print(char c[]){cout<<c<<endl; }
};
int main(){printData pd;pd.print(3);return 0;
}
重载运算符
语法格式:
class 类名
{
public:返回类型 operator 运算符 (参数列表){// 运算符的具体运算过程}
}
普通成员函数,以标识符作为函数名。
而重载函数,以 "operator 函数名" 作为函数名。其中operator 表示这是一个重载的运算符。
而后的运算符,就是我们要定义的符号。
如:
a+b;
实际等同于
a.operator + (b)
实例操作:
class Box
{private:double length; // 长度double breadth; // 宽度double height; // 高度// 重载 + 运算符,用于把两个 Box 对象相加Box operator+(const Box& b){Box box;box.length = this->length + b.length;box.breadth = this->breadth + b.breadth;box.height = this->height + b.height;return box;}};Box3 = Box1 + Box2;
为啥用 this 时,有->:
在 C++ 中,每一个非静态成员函数都有一个隐含的指针形参,即this指针。
this指针指向调用该成员函数的对象,它是一个常量指针,其类型为类名* const 。
期望 :: 数学知识 ::
期望的由来赌硬币
基础忘记时,可以看看堵硬币

借鉴博客:
1、C++ 重载运算符和重载函数
2、C++中的运算符重载(非常详细)
3、【原创】优先队列 priority_queue 详解
( •̀ ω •́ )✧点击这里,继续学习其他模块吧!
相关文章:
优先队列 priority_queue详解
说到,priority_queue优先队列。必须先要了解啥是堆与运算符重载(我在下方有解释)。 否则只知皮毛,极易忘记寸步难行。 但在开头,还是简单的说下怎么用 首先,你需要调用 #include <queue> 在main函数中,声明…...
《信息系统安全》(第一次上机实验报告)
实验一 :网络协议分析工具Wireshark 一 实验目的 学习使用网络协议分析工具Wireshark的方法,并用它来分析一些协议。 二实验原理 TCP/IP协议族中网络层、传输层、应用层相关重要协议原理。网络协议分析工具Wireshark的工作原理和基本使用规则。 三 实…...
C++实现求解24点游戏
力扣原题:679. 24 点游戏 - 力扣(LeetCode) 判断四个数字能否通过加减乘除得到24点 使用回溯遍历四个数字的每一种组合,具体来说,每次从数组中选取两个数字以加减乘除四种方式得到一个新的数字,这样数组的…...
Java-腾讯云短信模板兼容阿里云短信模板-短信模板参数生成
最新版本更新 https://code.jiangjiesheng.cn/article/362?fromcsdn 模板 腾讯云:您好!{}的${},有{}发生{} 阿里云:您好!${orgName}的${monitorName},有${equipName}发生${status} 原腾讯云短信发送的代码…...
简要分析IPPROTO_TCP参数
IPPROTO_TCP是操作系统或网络编程中定义的一个 协议号常量,用于标识 传输控制协议(TCP)。其核心作用是 在传输层指定使用TCP协议,确保数据通过TCP的可靠传输机制进行通信。 一、定义与值 头文件:定义在<netinet/in.…...
SOFABoot-06-健康检查
前言 大家好,我是老马。 sofastack 其实出来很久了,第一次应该是在 2022 年左右开始关注,但是一直没有深入研究。 最近想学习一下 SOFA 对于生态的设计和思考。 sofaboot 系列 SOFABoot-00-sofaboot 概览 SOFABoot-01-蚂蚁金服开源的 s…...
如何理解java中Stream流?
在Java中,Stream 是 Java 8 引入的一个强大API,用于处理集合(如 List、Set、Map 等)数据的流式操作。它提供了一种声明式、函数式的编程风格,可以高效地进行过滤、映射、排序、聚合等操作。 Stream 的核心概念 流&…...
Android使用RxHttp进行国密4加密解密
国密SM4加解密问题汇总 前言国密4加解密工具类RxHttp统一加解密处理解密前言 为了网络安全需要对app内请求数据接口使用SM4国密4进行加解密操作,在实施的过程中遇到了些问题 也收获颇丰,特此记录 在线SM4加密测试网址: 点击此进入网址. 国密4加解密工具类 这里我使用的是b…...
【自学笔记】Linux基础知识点总览-持续更新
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 Linux 基础知识点总览目录Linux 简介文件和目录结构常用命令文件操作目录操作权限管理文本处理 Shell 脚本基础进程管理用户和组管理网络配置 总结 Linux 基础知识点…...
JavaScript与客户端开发
1、简介 简单的讲,JavaScript是一种脚本语言,为网站提供了一种在客户端运行程序的手段,通过它可以实现客户端数据验证、网页特效等功能。 JavaScript是一种基于对象和事件驱动(不懂啥意思,暂不管它)&…...
基于CNN的FashionMNIST数据集识别5——GoogleNet模型
源码 import torch from torch import nn from torchsummary import summaryclass Inception(nn.Module):def __init__(self, in_channels, c1, c2, c3, c4):super().__init__()self.ReLu nn.ReLU()#路径1self.p1_1 nn.Conv2d(in_channelsin_channels, out_channelsc1, kern…...
JVM垃圾回收笔记01-垃圾回收算法
文章目录 前言1. 如何判断对象可以回收1.1 引用计数法1.2 可达性分析算法查看根对象哪些对象可以作为 GC Root ?对象可以被回收,就代表一定会被回收吗? 1.3 引用类型1.强引用(StrongReference)2.软引用(SoftReference…...
【初探数据结构】树与二叉树
💬 欢迎讨论:在阅读过程中有任何疑问,欢迎在评论区留言,我们一起交流学习! 👍 点赞、收藏与分享:如果你觉得这篇文章对你有帮助,记得点赞、收藏,并分享给更多对数据结构感…...
numpy学习笔记10:arr *= 2向量化操作性能优化
numpy学习笔记10:arr * 2向量化操作性能优化 在 NumPy 中,直接对整个数组进行向量化操作(如 arr * 2)的效率远高于显式循环(如 for i in range(len(arr)): arr[i] * 2)。以下是详细的解释: 1. …...
蓝桥杯备考:二分答案之路标设置
最大距离,找最小空旷指数值,我们是很容易想到用二分的,我们再看看这个答案有没有二段性 是有这么个二段性的,我们只要二分就行了,但是二分的check函数是有点不好想的,我们枚举空旷值的时候,为了…...
回调方法传参汇总
文章目录 0. 引入问题1. 父子组件传值1.1 父传子:props1.2 子传父:$emit1.3 双向绑定:v-model 2. 多个参数传递3. 父组件监听方法传递其他值3.1 $event3.2 箭头方法 4. 子组件传递多个参数,父组件传递本地参数4.1 箭头函数 … 扩…...
在 Linux下使用 Python 3.11 和 FastAPI 搭建带免费证书的 HTTPS 服务器
在当今数字化时代,保障网站数据传输的安全性至关重要。HTTPS 协议通过使用 SSL/TLS 加密技术,能够有效防止数据在传输过程中被窃取或篡改。本教程将详细介绍如何在 Ubuntu 22.04 系统上,使用 Python 3.11 和 FastAPI 框架搭建一个带有免费 SS…...
XSS基础靶场练习
目录 1. 准备靶场 2. PASS 1. Level 1:无过滤 源码: 2. level2:转HTML实体 htmlspecialchars简介: 源码 PASS 3. level3:转HTML深入 源码: PASS 4. level4:过滤<> 源码: PASS: 5. level5:过滤on 源码…...
Redis核心机制(一)
目录 Redis的特性 1.速度快 2.以键值对方式进行存储 3.丰富的功能 4.客户端语言多 5.持久化 6.主从复制 7.高可用和分布式 Redis使用场景 Redis核心机制——持久化 RDB bgsave执行流程 编辑 AOF AOF重写流程 3.混合持久化(RDBAOF) Red…...
QGroupBox取消勾选时不禁用子控件
默认情况下,QGroupBox取消勾选会自动禁用子控件,如下图所示 那么如何实现取消勾选时不禁用子控件呢? 实现很简单,直接上代码了 connect(ui->groupBox, &QGroupBox::toggled, this, [](bool checked){if (checked false){…...
Go语言中package的使用规则《二》
在 Go 语言中,包(Package) 是代码组织和复用的核心单元。以下是其定义、引用规则及使用习惯的详细说明: 一、包的定义规则 目录与包名 一个包对应一个目录(文件夹),目录名通常与包名一致。 包名…...
MyBatis-Plus 自动填充:优雅实现创建/更新时间自动更新!
目录 一、什么是 MyBatis-Plus 自动填充? 🤔二、自动填充的原理 ⚙️三、实际例子:创建时间和更新时间字段自动填充 ⏰四、注意事项 ⚠️五、总结 🎉 🌟我的其他文章也讲解的比较有趣😁,如果喜欢…...
canvas数据标注功能简单实现:矩形、圆形
背景说明 基于UI同学的设计,在市面上找不到刚刚好的数据标注工具,遂决定自行开发。目前需求是实现图片的矩形、圆形标注,并获取标注的坐标信息,使用canvas可以比较方便的实现该功能。 主要功能 选中图形,进行拖动 使…...
Python 魔术方法深度解析:__getattr__ 与 __getattribute__
一、核心概念与差异解析 1. __getattr__ 的定位与特性 触发时机: 当访问对象中 **不存在的属性** 时自动触发,是 Python 属性访问链中的最后一道防线。 核心能力: 动态生成缺失属性实现优雅的错误处理构建链式调用接口(如 R…...
【机器学习】机器学习工程实战-第2章 项目开始前
上一章:第1章 概述 文章目录 2.1 机器学习项目的优先级排序2.1.1 机器学习的影响2.1.2 机器学习的成本 2.2 估计机器学习项目的复杂度2.2.1 未知因素2.2.2 简化问题2.2.3 非线性进展 2.3 确定机器学习项目的目标2.3.1 模型能做什么2.3.2 成功模型的属性 2.4 构建机…...
【UI设计】一些好用的免费图标素材网站
阿里巴巴矢量图标库https://www.iconfont.cn/国内最大的矢量图标库之一,拥有 800 万 图标资源。特色功能包括团队协作、多端适配、定制化编辑等,适合企业级项目、电商设计、中文产品开发等场景。IconParkhttps://iconpark.oceanengine.com/home字节跳动…...
Visual Studio(VS)的 Release 配置中生成程序数据库(PDB)文件
最近工作中的一个测试工具在测试多台设备上使用过程中闪退,存了dump,但因为是release版本,没有pdb,无法根据dump定位代码哪块出了问题,很苦恼,查了下怎么加pdb生成,记录一下。以下是具体的设置步…...
ubuntu 解挂载时提示 “umount: /home/xx/Applications/yy: target is busy.”
问题如题所示,我挂载一个squanfs文件系统到指定目录,当我使用完后,准备解挂载时,提示umount: /home/xx/Applications/yy: target is busy.,具体的如图所示, 这种提示通常是表明这个路径的内容正在被某些进…...
一条不太简单的TEX学习之路
目录 rule raisebox \includegraphics newenviro 、\vspace \stretch \setlength 解释: 总结: 、\linespread newcommand \par 小四 \small simple 、mutiput画网格 解释: 图案解释: xetex pdelatex etc index 报…...
Matplotlib完全指南:数据可视化从入门到实战
目录 引言 一、环境配置与基础概念 1.1 安装Matplotlib 1.2 导入惯例 1.3 两种绘图模式 二、基础图形绘制 2.1 折线图(Line Plot) 2.2 柱状图(Bar Chart) 三、高级图表类型 3.1 散点图(Scatter Plotÿ…...
