[C++]priority_queue的介绍及模拟实现

目录

priority_queue的介绍及模拟实现::

                                                        priority_queue的介绍

                                                        priority_queue的定义方式

                                                        priority_queue各个接口的使用

                                                        堆的向上调整算法

                                                        堆的向下调整算法

                                                        仿函数

                                                        priority_queue的模拟实现

                                                        反向迭代器的底层原理

                                                        反向迭代器的模拟实现


priority_queue的介绍及模拟实现::

priority_queue的介绍

优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆的向上调整和向下调整算法将vector中的元素构造成堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。

#include <queue>
int main()
{priority_queue<int> pq;pq.push(3);pq.push(1);pq.push(2);pq.push(5);while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;return 0;
}

#include <functional>
#include <queue>
int main()
{priority_queue<int,vector<int>,greater<int>> pq;pq.push(3);pq.push(1);pq.push(2);pq.push(5);while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;return 0;
}

priority_queue的定义方式

方式一:使用vector作为底层容器,内部构造大堆结构

priority_queue<int,vector<int>,less<int>> pq1;

方式二:使用vector作为底层容器,内部构造小堆结构

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

方式三:不指定底层容器,默认为大堆结构

priority_queue<int> pq3;

priority_queue各个接口的使用

成员函数功能
push插入元素到队尾并调整为堆结构
pop弹出堆顶元素
top访问堆顶元素
size获取队列中有效元素个数
empty判断队列是否为空
swap交换两个队列的内容

priority_queueOJ:数组中第K大的元素

//方法一:建大堆 再popK次
class Solution 
{
public:int findKthLargest(vector<int>& nums, int k) {priority_queue<int> pq(nums.begin(), nums.end());while (--k){pq.pop();}return pq.top();}
};
//方法二:建K个数的小堆 和堆顶数据比较
class Solution
{
public:int findKthLargest(vector<int>& nums, int k){priority_queue<int, vector<int>, greater<int>> pq(nums.begin(), nums.begin() + k);for (size_t i = k; i < nums.size(); ++i){if (nums[i] > pq.top()){pq.pop();pq.push(nums[i]);}}return pq.top();}
};

堆的向上调整算法

思想:

1.将目标结点与父结点进行比较

2.若目标结点的值比父节点的值大,则交换目标结点与其父节点的位置,并将原目标节点的父节点当作新的目标节点继续进行向上调整,若目标节点的值比其父节点的值小,则停止向上调整。

void AdjustUp(vector<int>& v, size_t child)
{size_t parent = (child - 1) / 2;while (child > 0){if (v[child] > v[parent]){swap(v[child], v[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}

堆的向下调整算法

思想:

1.将目标节点与其较大的子节点进行比较

2.若目标节点的值比其较大的子节点的值小,则交换目标节点与其较大的子节点的位置,并将原目标节点的较大子节点当作新的目标节点继续进行向下调整,若目标节点的值比其较大子节点的值大,则停止向下调整。

void AdjustDown(vector<int>& v, int n , size_t parent)
{size_t child = 2 * parent + 1;while (child < v.size()){if (child + 1 < n && v[child] < v[child + 1]){++child;}if (v[parent] < v[child]){std::swap(v[child], v[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}

仿函数

仿函数的介绍:

namespace wjq
{template <class T>struct less{bool operator()(const T& x, const T& y){return x < y;}};template <class T>struct greater{bool operator()(const T& x, const T& y){return x > y;}};
}
int main()
{wjq::less<int> lessFunc;lessFunc(1, 2);return 0;
}

仿函数的使用场景:

bool cmp(int x, int y)
{return y > x;
}
void BubbleSort(int* a, int n, bool(*pcom)(int, int))
{for (int i = 0; i < n; i++){int exchange = 0;for (int j = 1; j < n - i; j++){if (pcom(a[j - 1] , a[j])){std::swap(a[j - 1], a[j]);exchange = 1;}}if (exchange == 0){break;}}
}
int main()
{int a[] = { 2,3,4,5,6,1,4,9 };BubbleSort(a, 8, cmp);for (size_t i = 0; i < 8; i++){cout << a[i] << " ";}cout << endl;return 0;
}

namespace wjq
{template <class T>struct less{bool operator()(const T& x, const T& y){return x < y;}};template <class T>struct greater{bool operator()(const T& x, const T& y){return x > y;}};
}
template<class T,class Compare>
void BubbleSort(T* a, int n, Compare com)
{for (int i = 0; i < n; i++){int exchange = 0;for (int j = 1; j < n - i; j++){if (com(a[j], a[j - 1])){std::swap(a[j - 1], a[j]);exchange = 1;}}if (exchange == 0){break;}}
}
int main()
{wjq::less<int> lessFunc;int a[] = { 2,3,4,5,6,1,4,9 };BubbleSort(a, 8, lessFunc);for (size_t i = 0; i < 8; i++){cout << a[i] << " ";}cout << endl;return 0;
}

仿函数的特殊使用场景:

如果在priority_queue中放自定义类型的数据,用户需要自己提供>和<的重载

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& out, const Date& d){out << d._year << "-" << d._month << "-" << d._day;return out;}
private:int _year;int _month;int _day;
};
void TestPriorityQueue()
{// 大堆,需要用户在自定义类型中提供<的重载priority_queue<Date> q1;q1.push(Date(2023, 12, 1));q1.push(Date(2023, 12, 2));q1.push(Date(2023, 11, 30));cout << q1.top() << endl;// 如果要创建小堆,需要用户提供>的重载priority_queue<Date, vector<Date>, greater<Date>> q2;q2.push(Date(2023, 12, 1));q2.push(Date(2023, 12, 2));q2.push(Date(2023, 11, 30));cout << q2.top() << endl;
}
int main()
{TestPriorityQueue();return 0;
}

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& out, const Date& d){out << d._year << "-" << d._month << "-" << d._day;return out;}
private:int _year;int _month;int _day;
};
void TestPriorityQueue()
{//大堆priority_queue<Date*> q1;q1.push(new Date(2023, 12, 1));q1.push(new Date(2023, 12, 2));q1.push(new Date(2023, 11, 30));cout << q1.top() << endl;//小堆priority_queue<Date*> q2;priority_queue<Date*, vector<int>, greater<Date>> q2;q2.push(new Date(2023, 12, 1));q2.push(new Date(2023, 12, 2));q2.push(new Date(2023, 11, 30));cout << q2.top() << endl;
}
int main()
{TestPriorityQueue();return 0;
}

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& out, const Date& d){out << d._year << "-" << d._month << "-" << d._day;return out;}
private:int _year;int _month;int _day;
};
struct PDateLess
{bool operator()(const Date* d1, const Date* d2){return *d1 < *d2;}
};
struct PDateGreater
{bool operator()(const Date* d1, const Date* d2){return *d1 > *d2;}
};
void TestPriorityQueue()
{//大堆priority_queue<Date*, vector<Date*>, PDateLess> q1;q1.push(new Date(2023, 12, 1));q1.push(new Date(2023, 12, 2));q1.push(new Date(2023, 11, 30));cout << *q1.top() << endl;//小堆priority_queue<Date*, vector<Date*>, PDateGreater> q2;q2.push(new Date(2023, 12, 1));q2.push(new Date(2023, 12, 2));q2.push(new Date(2023, 11, 30));cout << *q2.top() << endl;
}
int main()
{TestPriorityQueue();return 0;
}

priority_queue的模拟实现

namespace wjq
{template <class T>struct less{bool operator()(const T& x, const T& y){return x < y;}};template <class T>struct greater{bool operator()(const T& x, const T& y){return x > y;}};template <class T, class Container = std::vector<T>, class Compare = less<int>>class priority_queue{private:void AdjustUp(size_t child){Compare com;//构造一个仿函数对象size_t parent = (child - 1) / 2;while (child > 0){if (com(_con[parent], _con[child])){swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void AdjustDown(size_t parent){Compare com;//构造一个仿函数对象size_t child = 2 * parent + 1;while (child < _con.size()){if (child + 1 < _con.size() && com(_con[child], _con[child + 1])){++child;}if (com(_con[parent], _con[child])){std::swap(_con[child], _con[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}public://无参构造函数priority_queue(){//默认构造函数即可}//迭代器区间构造template <class InputIterator>priority_queue(InputIterator first, InputIterator last):_con(first, last){for (int i = (_con.size() - 1 - 1) / 2; i >= 0; --i){AdjustDown(i);}}void push(const T& x){_con.push_back(x);AdjustUp(_con.size() - 1);//从size-1开始调整}void pop(){std::swap(_con[0], _con[_con.size() - 1]);//交换首尾数据_con.pop_back();//尾删AdjustDown(0);}const T& top() const{return _con[0];}bool empty() const{return _con.empty();}size_t size()const{return _con.size();}private:Container _con;};
}

反向迭代器的底层原理

反向迭代器的本质就是对正向迭代器的封装,它同样是一个适配器。

STL源码中的反向迭代器的实现:反向迭代器用正向迭代器进行构造。

typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;
reverse_iterator rbegin() 
{ return reverse_iterator(end());
}
reverse_iterator rend() 
{ return reverse_iterator(begin());
}

STL源码中,其实正向迭代器和反向迭代器的位置是对称的。通过图示,rbegin()迭代器是最后一个数据的下一个位置,但是通过rbegin()访问的数据应该是6,这是通过运算符重载operator*()来解决。

template <class Iterator, class Ref, class Ptr>
Ref operator*()
{Iterator tmp = _it;return *(--tmp);
}

反向迭代器的模拟实现

namespace wjq
{template <class Iterator, class Ref, class Ptr>class ReverseIterator{public:RevserseIterator(Iterator it)//使用正向迭代器构造反向迭代器:_it(it){}Ref operator*(){Iterator tmp = _it;return *(--tmp);}Ptr operator->(){return &(operator*());}typedef ReverseIterator<Iterator, Ref, Ptr> SelfSelf& operator++(){--_it;return *this;}Self& operator--(){++_it;return *this;}bool operator!=(const Self& s) const{return _it != s._it;}private:Iterator _it;//底层是传入类型的迭代器};
}

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

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

相关文章

SWD和JTAG

1、调试接口概念 1&#xff09;SWD&#xff1a;Serial Wire Debug&#xff0c;代表串行线调试&#xff0c;是ARM设计的协议&#xff0c;用于对其微控制器进行编程和调试。 SWD 引脚&#xff1a; SWDIO–串行数据线&#xff0c;用于数据的读出和写入SWDCLK–串行时钟线&#…

前端开发_CSS

CSS定义 层叠样式表 (Cascading Style Sheets&#xff0c;缩写为 CSS&#xff09;&#xff0c;是一种 样式表 语言&#xff0c;用来描述 HTML 文档的呈现&#xff08;美化内容&#xff09; 书写位置&#xff1a;title 标签下方添加 style 双标签&#xff0c;style 标签里面书…

内外网转换NAT

目录 分类 内核参数配置文件 SNAT 网关服务器配置 配置内网主机 配置外网主机 配置SNAT 内网主机测试 DNAT 配置网关服务器 支持的规则链&#xff1a;INPUT、OUTPUT、PREROUTING、POSTROUTING 分类 SNAT&#xff08;将外网设备共享给内网&#xff09; source NAT &a…

关于rocketMQ踩坑的那些事

在最近&#xff0c;我所写的这个项目需要使用到rocketMQ&#xff0c;为了图方便我便使用的是Windows版本的&#xff0c;但是在使用的过程中首先是发现无法发送消息出去&#xff0c;报错信息为 org.apache.rocketmq.client.exception.MQClientException: Send [3] times, still …

分布式搜索引擎elasticsearch(二)

1.DSL查询文档 elasticsearch的查询依然是基于JSON风格的DSL来实现的。 1.1.DSL查询分类 Elasticsearch提供了基于JSON的DSL(Domain Specific Language)来定义查询。常见的查询类型包括: 查询所有:查询出所有数据,一般测试用。例如:match_all 全文检索(full text)查…

Spring Bean的生命周期各阶段详解附源码

目录 Bean的生命周期Bean定义阶段Bean实例化阶段Bean属性注入阶段Bean初始化阶段Bean销毁阶段 Bean的生命周期 bean的生命周期&#xff0c;我们都知道大致是分为&#xff1a;bean定义&#xff0c;bean的实例化&#xff0c;bean的属性注入&#xff0c;bean的初始化以及bean的销毁…

基础课14——语音识别

ASR 是自动语音识别&#xff08;Automatic Speech Recognition&#xff09;的缩写&#xff0c;是一种将人类语音转换为文本的技术。ASR 系统可以处理实时音频流或已录制的音频文件&#xff0c;并将其转换为文本。它是一种自然语言处理技术&#xff0c;广泛应用于许多领域&#…

卷积神经网络(CNN):乳腺癌识别.ipynb

文章目录 一、前言一、设置GPU二、导入数据1. 导入数据2. 检查数据3. 配置数据集4. 数据可视化 三、构建模型四、编译五、训练模型六、评估模型1. Accuracy与Loss图2. 混淆矩阵3. 各项指标评估 一、前言 我的环境&#xff1a; 语言环境&#xff1a;Python3.6.5编译器&#xf…

VQD视频质量诊断服务/图像质量诊断/视频流质量诊断/传统方法与深度学习结合的视频质量诊断

随着平安城市、大安防的发展&#xff0c;监控摄像机数量的不断增加&#xff0c;给监控系统的维护工作带来了新的挑战。如何及时了解前端视频设备的运行情况&#xff0c;发现故障并检测恶意遮挡与破坏的不法行为已成为视频监控系统运行的首要迫切问题。对于成千上万个监控摄像机…

TCP 半连接队列和全连接队列

在 TCP 三次握手的时候&#xff0c;Linux 内核会维护两个队列&#xff0c;分别是&#xff1a; 半连接队列&#xff0c;也称 SYN 队列&#xff1b; 全连接队列&#xff0c;也称 accept 队列&#xff1b; 服务端收到客户端发起的 SYN 请求后&#xff0c;内核会把该连接存储到半连…

java 多种验证码

java 多种验证码 1.SpringBoot 引入jar包2. java 导入jar包3. 代码4. 效果图 1.SpringBoot 引入jar包 <dependency><groupId>com.github.whvcse</groupId><artifactId>easy-captcha</artifactId><version>1.6.2</version> </dep…

Spring Boot中使用Swagger

1. 启用Swagger 1.1 启用注解扫描和文档接口 直接在POM文件引入依赖 <dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version> </dependency>1.2 启动swagger-u…

【Windows下】Eclipse 尝试 Mapreduce 编程

文章目录 配置环境环境准备连接 Hadoop查看 hadoop 文件 导入 Hadoop 包创建 MapReduce 项目测试 Mapreduce 编程代码注意事项常见报错 配置环境 环境准备 本次实验使用的 Hadoop 为 2.7.7 版本&#xff0c;实验可能会用到的文件 百度网盘链接&#xff1a;https://pan.baidu…

Shopee过期的折扣活动如何删除?Shopee促销商品如何下架?——站斧浏览器

商家们可以轻松删除虾皮过期活动以及下架促销商品&#xff0c;保持店铺的整洁和顾客的购物体验。那么shopee过期的折扣活动如何删除&#xff0c;shopee促销商品如何下架。 Shopee过期的折扣活动如何删除&#xff1f; 在删除虾皮过期活动时&#xff0c;商家们需要遵循以下步骤…

Deployment脚本部署Tomcat集群:外部访问、负载均衡、文件共享及集群配置调整

文章目录 前置知识一、Deployment脚本部署Tomcat集群二、外部访问Tomcat集群三、利用Rinted对外提供Service负载均衡支持1、创建服务2、端口转发工具Rinetd3、定义jsp文件查看转发到哪个节点 四、部署配置挂载点五、基于NFS实现集群文件共享1、master2、node3、验证 六、集群配…

Linux 进程

文章目录 进程定义进程的描述查看进程方法进程状态进程优先级进程相关概念补充 进程定义 大多数的说法&#xff1a;进程是计算机中正在运行的程序的实例。它是操作系统对程序的一种抽象&#xff0c;用于管理和调度程序的执行。 个人理解: 从OS(操作系统)开始说起&#xff0c;…

用户态和内核态

实际上任何Linux发行版(Centos/RedHat....)&#xff0c;其系统内核都是Linux。我们的应用都需要通过Linux内核与硬件交互。为了避免用户应用导致冲突甚至内核崩溃&#xff0c;用户应用与内核是分离的&#xff1a; 进程的寻址空间会划分为两部分&#xff1a;内核空间、用户空间。…

记一次引入低版本包导致包冲突,表现为NoClassDefFoundError的故障

简而言之&#xff0c;因为参考别的项目处理excel的代码if(org.apache.poi.hssf.usermodel.HSSFDateUtil.isCellDateFormatted(cell)) &#xff0c;为了使用这个HSSFDateUtil类我引入了依赖&#xff1a; <dependency><groupId>org.apache.poi</groupId><a…

LED恒流开关调节器FP7123,提供稳定电流,提升LED产品效果!

目录 一、FP7123概述 二、FP7123功能 LED恒流开关调节器FP7123的优势不仅仅在于提供稳定的电流&#xff0c;还包括以下几个方面&#xff1a; 三、应用领域 随着科技的不断发展&#xff0c;LED照明产品已经成为人们生活中不可或缺的一部分。然而&#xff0c;LED的亮度和稳定性…

二维码智慧门牌管理系统升级解决方案:存疑地址轻松管理

文章目录 前言一、存疑地址的统一管理二、数据查询、导出和编辑功能三、提交地址审核机制 前言 随着二维码智慧门牌管理系统在企业中的广泛应用&#xff0c;地址存疑成为了一个亟待解决的问题。为了帮助企业有效管理这些存疑地址&#xff0c;我们推出了升级解决方案&#xff0…