做网站ps的图片/刚刚发生 北京严重发生
文章目录
- 一、priority_queue 的介绍和使用
- 1、priority_queue 的介绍
- 2、priority_queue 的使用
- 3、priority_queue 相关 OJ 题
- 二、仿函数
- 1、什么是仿函数
- 2、仿函数的作用
- 三、priority_queue 的模拟实现
一、priority_queue 的介绍和使用
1、priority_queue 的介绍
priority_queue (优先级队列) 是一种容器适配器,它与 queue 共用一个头文件,其底层结构是一个堆,并且默认情况下是一个大根堆,所以它的第一个元素总是它所包含的元素中最大的,并且为了不破坏堆结构,它也不支持迭代器:
同时,由于堆需要进行下标计算,所以 priority_queue 使用 vector 作为它的默认适配容器 (支持随机访问):
但是,priority_queue 比 queue 和 stack 多了一个模板参数 – 仿函数;关于仿函数的具体细节,我们将在后文介绍。
class Compare = less<typename Container::value_type>
2、priority_queue 的使用
优先级队列默认使用 vector 作为其底层存储数据的容器,在 vector 上又使用了堆算法将 vector 中元素构造成堆的结构,因此 priority_queue 就是堆,所有需要用到堆的位置,都可以考虑使用 priority_queue。(注意:默认情况下priority_queue是大堆)
priority_queue 的使用文档
-函数声明 | 接口说明- |
---|---|
priority_queue() | 构造一个空的优先级队列 |
priority_queue(first, last) | 迭代器区间构造优先级队列 |
empty( ) | 检测优先级队列是否为空 |
top( ) | 返回优先级队列中最大(最小元素),即堆顶元素 |
push(x) | 在优先级队列中插入元素x |
pop() | 删除优先级队列中最大(最小)元素,即堆顶元素 |
size() | 返回优先级队列中的元素个数 |
注意事项:
priority_queue 默认使用的仿函数是 less,所以默认建成的堆是大堆;如果我们想要建小堆,则需要指定仿函数为 greater,该仿函数包含在头文件 functional 中,并且由于仿函数是第三个缺省模板参数,所以如果要传递它必须先传递第二个模板参数即适配容器。
void test_priority_queue() {priority_queue<int> pq; //默认建大堆,仿函数为lesspq.push(5);pq.push(2);pq.push(4);pq.push(1);pq.push(3);while (!pq.empty()) {cout << pq.top() << " ";pq.pop();}cout << endl;priority_queue<int, vector<int>, greater<int>> pq1; //建小堆,仿函数为greater,需要显式指定pq1.push(5);pq1.push(2);pq1.push(4);pq1.push(1);pq1.push(3);while (!pq1.empty()) {cout << pq1.top() << " ";pq1.pop();}cout << endl;
}
3、priority_queue 相关 OJ 题
215. 数组中的第K个最大元素 - 力扣(LeetCode)
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例
输入: [3,2,1,5,6,4], k = 2 输出: 5输入: [3,2,3,1,2,4,5,5,6], k = 4 输出: 4
思路1
思路1非常简单,直接对 nums 数组使用 sort 进行排序,然后返回 nums[nums.size() - k] 即可,但是排序的时间复杂度为 O(N*logN),太高。
思路2
思路2就是建N个数的大堆,然后 pop k-1 次,此时堆顶元素就是第 K 大的数,向下调整建堆时间复杂度为 O(N),pop 再向下调整的时间复杂度为 K*logN,所以总的时间复杂度为 O(N + K*logN);此方法可行,但是当 N 很大,K 很小时,空间复杂度过高。
思路3
建 K 个数的小堆,剩余 N- K 个数依次与堆顶元素进行比较,如果大于堆顶元素就将堆顶元素 pop 掉,然后将其 push 进堆中,最后堆顶元素就是第 K 大的数;建堆的时间复杂度为 O(K),push 再向上调整的时间复杂度为 O((N-k)*logK),所以总的时间复杂度为 O(K + (N-k) * logK);此方法在 N 很大,K 很小的情况下依然适用,因为堆的大小固定为 K。
代码实现
class Solution {
public:int findKthLargest(vector<int>& nums, int k) {priority_queue<int, vector<int>, greater<int>> pq; //建小堆for(int i = 0; i < k; i++) { //建K个数的小堆pq.push(nums[i]);}for(int i = k; i < nums.size(); i++) { //剩余n-k个数与堆顶比较,大于就删除堆顶元素入堆if(nums[i] > pq.top()) {pq.pop();pq.push(nums[i]);}}return pq.top(); //堆顶元素为第K大的数}
};
二、仿函数
1、什么是仿函数
仿函数也叫函数对象,仿函数是一个类,但是该类必须重载函数调用运算符 (),即 operator()(参数);由于这样的类的对象可以像函数一样去使用,所以我们将其称为仿函数/函数对象,如下:
namespace thj {template<class T>struct less {bool operator()(const T& x, const T& y) const {return x < y;}};template<class T>struct greater {bool operator()(const T& x, const T& y) {return x > y;}};
}void functor_test() {thj::less<int> lessFunc;cout << lessFunc(1, 2) << endl; //lessFunc.operator(1,2)thj::greater<int> greaterFunc;cout << greaterFunc(1, 2) << endl; //greaterFunc.operator(1,2)
}
可以看到,因为 less 类和 greater 类重载了 () 操作符,所以类对象可以像函数一样去使用,因此它们被称为仿函数。
2、仿函数的作用
我们以最简单的冒泡排序为例来说明仿函数的作用,我们知道,排序分为排升序和排降序,那么在没有仿函数的时候,即C语言阶段,我们是如何来解决这个问题的呢 – 答案是函数指针;
将排序函数的最后一个参数定义为函数指针,然后通过用户给排序函数传递不同的比较函数来决定升序还是降序:
template<class T>
bool cmpUp(const T& e1, const T& e2) { //排升序return e1 > e2;
}template<class T>
bool cmpDown(const T& e1, const T& e2) { //排降序return e1 < e2;
}// 冒泡排序
template<class T>
void BubbleSort(T* a, int n, bool (*cmp)(const T&, const T&))
{T i = 0;T j = 0;for (i = 0; i < n - 1; i++){int exchange = 0;for (j = 0; j < n - i - 1; j++){if (cmp(a[j], a[j + 1])) //函数调用{std::swap(a[j], a[j + 1]);exchange = 1;}}if (exchange == 0) break;}
}void bubbleSort_test() {int a[] = { 1, 3, 2, 2, 4, 8, 5, 1, 9 };BubbleSort(a, sizeof(a) / sizeof(int), cmpUp);for (auto e : a) {cout << e << " ";}cout << endl;int b[] = { 1, 3, 2, 2, 4, 8, 5, 1, 9 };BubbleSort(b, sizeof(b) / sizeof(int), cmpDown);for (auto e : b) {cout << e << " ";}cout << endl;
}
在 C++ 中,我们不再使用函数指针解决升序降序的问题,转而使用更加方便的仿函数。(注:关于仿函数的更多细节以及仿函数和函数指针各自的优缺我们将在以后慢慢学习,现在仅仅是浅浅入门一下仿函数)
// 冒泡排序
template<class T, class Compare>
void BubbleSort(T* a, int n, Compare cmp) //使用仿函数
{T i = 0;T j = 0;for (i = 0; i < n - 1; i++){int exchange = 0;for (j = 0; j < n - i - 1; j++){if (cmp(a[j], a[j + 1])) //函数调用 cmp.operator()(a[j], a[j+1]){std::swap(a[j], a[j + 1]);exchange = 1;}}if (exchange == 0) break;}
}//复用前面的 less 和 greater 类
void bubbleSort_test1() {int a[] = { 1, 3, 2, 2, 4, 8, 5, 1, 9 };BubbleSort(a, sizeof(a) / sizeof(int), thj::less<int>()); //排降序,匿名对象for (auto e : a) {cout << e << " ";}cout << endl;int b[] = { 1, 3, 2, 2, 4, 8, 5, 1, 9 };BubbleSort(b, sizeof(b) / sizeof(int), thj::greater<int>()); //排升序for (auto e : b) {cout << e << " ";}cout << endl;
}
三、priority_queue 的模拟实现
其实 priority_queue 的模拟实现我们已经做过了 – priority_queue 的底层是堆,而关于堆的C语言实现包括堆的应用 (堆排序与TopK问题) 我们在数据结构初阶都已经做过了,这里只是用类和对象,再加上容器适配器和仿函数将其封装起来而已,所以下面我就直接给出实现代码而不进行细节分析了,如果有疑问的同学可以回头看看我之前的博客。
【数据结构】二叉树 – 堆
【数据结构】堆的应用 – 堆排序和TopK问题
priority_queue.h:
#pragma oncenamespace thj {//仿函数template<class T>struct less {bool operator()(const T& x, const T& y) const {return x < y;}};template<class T>struct greater {bool operator()(const T& x, const T& y) {return x > y;}};//priority_queuetemplate<class T, class Container = vector<T>, class Compare = less<T>> //默认建大堆,传lessclass priority_queue {public:priority_queue() {} //默认构造template<class InputIterator>priority_queue(InputIterator first, InputIterator last) //迭代器区间构造: _con(first, last){//向下调整建堆 O(N) 从最后一个非叶子节点开始for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--) {adjustDown(i);}}bool empty() const { //判空return _con.empty();}size_t size() const { //元素个数return _con.size();}const T& top() const { //取堆顶数据return _con[0];}void push(const T& x) { //插入数据_con.push_back(x);adjustUp(_con.size() - 1); //从最后一个节点开始向上调整}void pop() { //删除堆顶数据std::swap(_con[0], _con[_con.size() - 1]); //为了不破坏堆结构,先将第一个元素和最后一个交换_con.pop_back();adjustDown(0); //从堆顶向下调整}void adjustDown(size_t parent) { //堆的向下调整Compare cmp; //仿函数size_t child = parent * 2 + 1;while (child < _con.size()) { //特别注意边界问题if (child + 1 < _con.size() && cmp(_con[child], _con[child + 1])) { //仿函数child = child + 1; //如果是less,则建大堆,找大孩子,结果为真,右孩子大}if (cmp(_con[parent], _con[child])) {std::swap(_con[parent], _con[child]);//迭代parent = child;child = parent * 2 + 1;}else break; //满足堆结构,跳出循环}}void adjustUp(size_t child) { //堆的向上调整Compare cmp;size_t parent = (child - 1) / 2;while (child > 0) { //一直向上调整到根节点if (cmp(_con[parent], _con[child])) {std::swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else break;}}private:Container _con;};
}
test.cpp:
#include "priority_queue.h"
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
using namespace std;void my_priority_queue_test() {thj::priority_queue<int> pq; //默认建大堆,仿函数为lesspq.push(5);pq.push(2);pq.push(4);pq.push(1);pq.push(3);while (!pq.empty()) {cout << pq.top() << " ";pq.pop();}cout << endl;thj::priority_queue<int, vector<int>, thj::greater<int>> pq1; //建小堆,仿函数为greater,需要显式指定pq1.push(5);pq1.push(2);pq1.push(4);pq1.push(1);pq1.push(3);while (!pq1.empty()) {cout << pq1.top() << " ";pq1.pop();}cout << endl;std::vector<int> v;v.push_back(1);v.push_back(8);v.push_back(2);v.push_back(3);v.push_back(6);thj::priority_queue<int> pq2(v.begin(), v.end()); //迭代器区间构造while (!pq2.empty()) {cout << pq2.top() << " ";pq2.pop();}cout << endl;
}
相关文章:

【C++】仿函数 -- priority_queue
文章目录一、priority_queue 的介绍和使用1、priority_queue 的介绍2、priority_queue 的使用3、priority_queue 相关 OJ 题二、仿函数1、什么是仿函数2、仿函数的作用三、priority_queue 的模拟实现一、priority_queue 的介绍和使用 1、priority_queue 的介绍 priority_queu…...

盘一盘C++的类型描述符(一)
前言 C的类型描述方式是从C语言继承来的,并且进行了扩充(例如引用、非静态成员函数、模板实参等)。但由于C语言中的类型描述方式就略微有点「反人类」,再经C扩展后就有点「反碳基生物」了~ 是的,当我第一次看到这种描…...

Peppol的发展史和基本框架
Peppol(Pan-European Public Procurement Online)是欧洲区域内的一个跨境公共采购电子商务平台试点项目,由欧盟委员会和Peppol联盟成员国共同资助建立,旨在通过制定标准化框架,推动欧盟成员国在公共采购相关的电子目录…...

Linux-GCC介绍+入门级Makefile使用
前言(1)我们都知道,在Linux中编译.c文件需要使用gcc -o .c文件的指令来将C文件变成可执行文件。但是我们有没有发现,如果我们需要编译大一点的工程,后面需要加上的.c文件是不是太多了?感觉非常的麻烦。&…...

iOS(一):Swift纯代码模式iOS开发入门教程
Swift纯代码模式iOS开发入门教程项目初始化(修改为纯代码项目)安装第三方库(以SnapKit库为例)桥接OC库(QMUIKit)封装视图并进行导航跳转示例:使用 TangramKit 第三方UI布局库应用国际化添加 R.s…...

IDEA+Python+Selenium+360浏览器自动化测试
环境配置前提,见文章https://mp.csdn.net/mp_blog/creation/editor/new?spm1001.2101.3001.4503下载360浏览器,并下载对应版本的chromedriver.exe,下载地址http://chromedriver.storage.googleapis.com/index.html下载好360浏览器࿰…...

运输层概述及web请求
运输层 运输层概述 运输层向高层用户屏蔽了下面网络核心的细节(如网络拓扑、所采用的路由选择协议等)它使应用进程看见的就好像是在两个运输层实体之间有一条端到端的逻辑通信信道; 根据需求不同,运输层提供两种运输协议 面向连…...

python与pycharm从零安装
python(解释器)下载地址:Welcome to Python.orgpycharm(编译器)下载地址:PyCharm: the Python IDE for Professional Developers by JetBrains一、python的下载与安装到官网后根据步骤下载安装包后…...

叠氮试剂943858-70-6,Azidobutyric acid NHS ester,叠氮-C3-活性酯
1、试剂基团反应特点(Reagent group reaction characteristics):Azidobutyric acid NHS ester具有叠氮化物和NHS酯端基。西安凯新生物科技有限公司供应的叠氮化物可以与炔烃、DBCO和BCN进行铜催化的点击化学反应。NHS酯可以与胺基反应&#x…...

pycharm激活虚拟环境时报错:无法加载文件activate.ps1,因为在此系统上禁止运行脚本,Windows10系统
问题: ii_env\Scripts\activate : 无法加载文件 F:\gitlab\AutoFrame\ii_env\Scripts\Activate.ps1,因为在此系统上禁止运行脚本。 有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID135170 中的 about_Execution_Policies。 所在…...

刷题小抄4-数组
在Python中数组的功能由列表来实现,本文主要介绍一些力扣上关于数组的题目解法 寻找数组中重复的数字 题目链接 题目大意: 给出一个数组,数组长度为n,数组里的数字在[0,n-1]范围以内,数字可以重复,寻找出数组中任意一个重复的数字,返回结果 解法一 该题最基础的思路是使用字…...

Hbase安装
目录 上传压缩包 解压 改名 修改 Hbase 配置文件 修改base-env.sh 修改hbase-site.xml 配置环境变量 修改zookeeper配置文件 复制配置文件 修改zoo.cfg配置文件 修改myid 配置环境变量 刷新配置文件 启动Hbase 进入Hbase 查看版本号 查看命名空间 查看命名空…...

面向对象设计模式:结构型模式之代理模式
一、引入 访问 FB:代理服务器 二、代理模式 aka Surrogate 2.1 Intent 意图 Provide a surrogate (代理) or placeholder for another object to control access to it. 为另一个对象提供一个代理或占位符,以控制对它的访问。代理模式给某一个对象提…...

CCF大数据专家委员会十周年纪念庆典纪实:拥抱数字时代,展望科技未来
山河远阔,奋进十年,作为国内大数据领域最权威的学术组织,CCF大数据专家委员会(以下简称“大专委”)不忘初心,凝心聚力,见证并推动了过去10年来大数据技术生态在中国的建立、发展和成熟。 2023年…...

Qt学习3-Qt Creator四则运算计算器(哔站视频学习记录)
计算器中的“”按钮这部分的代码解释 目录 制作计算器中的“”按钮这部分的代码解释 一、代码部分 二、解释 三、思路 四、死循环! 一、代码部分 void Widget::on_equalButton_clicked() {QStack<int> s_num,s_opt; //声明两个int类型变量char opt[128…...

学习 Python 之 Pygame 开发魂斗罗(九)
学习 Python 之 Pygame 开发魂斗罗(九)继续编写魂斗罗1. 在子弹类中修改敌人发射子弹的位置2. 创建显示敌人子弹的函数3. 解决敌人不会向下掉落的问题4. 给敌人碰撞体组增加碰撞体5. 解决敌人叠加在一起的问题继续编写魂斗罗 在上次的博客学习 Python 之…...

最简单的SpringBoot+MyBatis多数据源实现
最简单的SpringBootMyBatis多数据源实现1.数据库准备2.环境准备3.代码部分3.1多数据源配置2.测试随着应用用户数量的增加,相应的并发请求的数量也会跟着不断增加,慢慢地,单个数据库已经没有办法满足频繁的数据库操作请求了,在某些…...

Spring Boot 3.0系列【8】核心特性篇之SpringApplication
有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot版本3.0.3 源码地址:https://gitee.com/pearl-organization/study-spring-boot3 文章目录 前言1. 启动应用2. 自定义 Banner3. 应用参数传递参数获取参数4. ApplicationRunner、CommandLineRunner5. 事件发布和监听…...

Nginx的搭建与核心配置
目录 一.Nginx是什么? 1.Nginx概述 2.Nginx模块与作用 3.Nginx三大作用:反向代理、负载均衡、动静分离 二.Nginx和Apache的差异 三.安装Nginx 1.编译安装 2.yum安装 四.Nginx的信号使用 五.Nginx的核心配置指令 1.访问状态统计配置 2.基于授…...

Java学习笔记 --- jQuery
一、jQuery介绍 jQuery,顾名思义,也就是JavaScript和查询(Query),它就是辅助JavaScript开发的js类库。它的核心思想是write less,do more(写得更少,做得更多),…...

华为OD机试题,用 Java 解【字符串加密】问题
华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不…...

软聚类算法:模糊聚类 (Fuzzy Clustering)
前言 如果你对这篇文章感兴趣,可以点击「【访客必读 - 指引页】一文囊括主页内所有高质量博客」,查看完整博客分类与对应链接。 在介绍模糊聚类之前,我们先简单地列举一下聚类算法的常见分类: 硬聚类 (Hard Clustering) Connec…...

Java Web 实战 02 - 多线程基础篇(1)
Java Web 实战 02 - 多线程基础篇 - 1一 . 认识线程1.1 概念1.1.1 什么是线程?1.1.2 为什么要有多个线程?1.1.3 进程和线程的区别(面试题)1.2 第一个多线程程序1.3 创建线程1.3.1 继承Thread类1.3.2 实现Runnable接口1.3.3 继承 Thread 类 , 使用匿名内部类1.3.4 实现 Runnab…...

C/C++开发,无可避免的多线程(篇三).协程及其支持库
一、c20的协程概念 在c20标准后,在一些函数中看到co_await、co_yield、co_return这些关键词,这是c20为协程实现设计的运算符。 协程是能暂停执行以在之后恢复的函数。原来我们调用一个功能函数时,只要调用了以后,就要完整执行完该…...

高级信息系统项目管理(高项 软考)原创论文项目背景合集
以下为原创的高项论文项目背景合集5篇,建议自己以此为基础,再多多打磨完善一下,避免雷同,同时使项目背景更加真实可信。 一、某市智慧工地系统建设项目 某市住建局智慧工地系统建设项目是在该市住建局促进建筑行业转型升级和科技创新,强化工程质量安全,推动建筑业高质量…...

锁屏面试题百日百刷-Hive篇(十一)
锁屏面试题百日百刷,每个工作日坚持更新面试题。锁屏面试题app、小程序现已上线,官网地址:https://www.demosoftware.cn。已收录了每日更新的面试题的所有内容,还包含特色的解锁屏幕复习面试题、每日编程题目邮件推送等功能。让你…...

一看就懂,等保2.0工作流程这么做
等保2.0相关国家标准于2019年12月1日开始实施,标志着我国网络安全等级保护工作进入一个崭新的阶段,对于加强我国网络安全保障工作,提升网络安全保护能力具有十分重要的意义。很多行业主管单位要求行业客户开展等级保护工作,合理地…...

Kerberos 域委派攻击之非约束性委派
CSDN文章自动迁移自博客在Windows 2000 Server 首次发布 Active Directory 时,Microsoft 必须提供一种简单的机制来支持用户通过 Kerberos 向 Web Server 进行身份验证并需要代表该用户更新后端数据库服务器上的记录的方案。这通常称为“Kerberos 双跳问题”&#x…...

【容器运行时】一文理解 OCI、runc、containerd、docker、shim进程、cri、kubelet 之间的关系
参考 docker,containerd,runc,docker-shim 之间的关系Containerd shim 进程 PPID 之谜内核大神教你从 Linux 进程的角度看 DockerRunC 简介OCI和runCContainerd 简介从 docker 到 runCDockershim究竟是什么技术干货|Docker和 Con…...

spark兼容性验证
前言 Apache Spark是专门为大规模数据处理而设计的快速通用的计算引擎,Spark拥有Hadoop MapReduce所具有的优点,但不同于Mapreduce的是Job中间输出结果可以保存在内存中,从而不再需要读写HDFS,因此Spark能更好的适用于数据挖掘与…...