【C++】优先级队列+反向迭代器

priority_queue的介绍

通常用堆来实现,能在O(log n)的时间复杂度内插入和提取最高(或最低)优先级的元素。
在这里插入图片描述

  1. 优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的(默认情况)。
  2. 此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)。
  3. 优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。
  4. 底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作
    empty():检测容器是否为空
    size():返回容器中有效元素个数
    front():返回容器中第一个元素的引用
    push_back():在容器尾部插入元素
    pop_back():删除容器尾部元素
  5. 标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector。
  6. 需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作。

弱排序标准是一种在数学和编程中用于定义元素之间排序关系的二元关系。它要求关系满足以下三个主要性质:
1.自反性:对于任何元素a,a与自身是相等的。
2.传递性:如果a小于b,且b小于c,则a小于c。
3.连通性:对于任何两个元素a和b,要么a小于b,要么b小于a

priority_queue的使用

1.默认情况下是大堆,其底层按照less比较;若创建小堆,将第三个模板参数换成greater的比较方式;
2.如果在priority_queue中放自定义类型的数据,用户需要在自定义类型中提供> 或者< 的重载。

数组中第k大的元素

在这里插入图片描述

大堆方法:第三个模板参数直接使用less排序,利用前置–的特性,k–
将优先级队列中的前k-1个元素删除掉
在这里插入图片描述

小堆方法:第三个模板参数要传入greater排序函数,运用topk问题思想,创建前k个元素的小堆,从数组的第k个元素开始遍历。如果当前元素大于堆顶元素(堆顶是最小值),则移除堆顶元素,并将当前元素加入堆。最后,堆顶元素即为数组中第k大的元素。
在这里插入图片描述

priority_queue的模拟实现

仿函数

又称函数对象,是类模板,通过重载()运算符,使得类模板的对象可以像函数一样被调用。
区分:函数模板要传对象,类模板要传参数是类型,不能加括号
在这里插入图片描述

向下调整

void Adjustdown(int parent)
{Compare com;int 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])){swap(_con[parent], _con[child]);parent = child;child = 2 * parent + 1;}elsebreak;}
}

通过比较器 Compare 确定堆的类型。用于从父节点开始向下调整堆结构,确保堆的性质得到满足。
作用:维护堆的性质,确保插入或移除操作后堆的结构仍然有效。
应用场景:插入新元素后或移除堆顶元素后调用。

向上调整

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

通过比较器 Compare 确定堆的类型。用于从子节点开始向上调整堆结构,确保堆的性质得到满足。
作用:维护堆的性质,确保插入新元素后堆的结构仍然有效。
应用场景:插入新元素后调用。

构造函数

在这里插入图片描述

复制元素:将迭代器范围内的所有元素复制到内部容器 _con 中。
构建堆:从最后一个非叶子节点开始,运用向下调整法逐步向上调整堆结构,确保堆的性质得到满足。

删除

在这里插入图片描述

交换堆顶元素与末尾元素,然后调用尾删函数,或者直接size–实现删除功能,再从堆顶即下标为0的位置开始向下调整来满足堆序

插入

在这里插入图片描述

插入新元素后,从最后索引位置size()-1来向上调整满足堆序。

自定义类测试(日期类)

	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);private:int _year;int _month;int _day;};ostream& operator<<(ostream& _cout, const Date& d){_cout << d._year << "-" << d._month << "-" << d._day;return _cout;}struct LessPDate{bool operator()(const Date* p1, const Date* p2){return *p1 < *p2;}};
}
void test_priority_queue2()
{priority_queue<Date*, vector<Date*>, LessPDate> pq;pq.push(new Date(2024, 6, 7));pq.push(new Date(2025, 1, 19));pq.push(new Date(2025, 10, 24));while (!pq.empty()){cout << *pq.top() << " ";pq.pop();}cout << endl;//测试仿函数的调用,与日期类无关Less<int>lessfunc;cout << lessfunc(10, 24) << endl;cout << lessfunc.operator()(10, 24) << endl;
}

优先级队列的定义:priority_queue<Date*, vector<Date*>, LessPDate> 表示优先级队列中存储的是 Date 类型的指针,底层容器是 vector,比较器是 LessPDate。
插入元素:通过 push 方法插入三个 Date 对象。
输出元素:通过 while 循环依次输出队列中的元素,直到队列为空。
在这里插入图片描述

整体代码

#pragma once
#include<vector>
#include<functional>//仿函数/函数对象
template <class T>
class Less
{
public:bool operator()(const T& x, const T& y){return x < y;}
};
template <class T>
class Greater
{
public:bool operator()(const T& x, const T& y){return x > y;}
};namespace ee
{template<class T,class Container=vector<T>, class Compare=less<T>>class priority_queue{private:void Adjustdown(int parent){Compare com;int 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])){swap(_con[parent], _con[child]);parent = child;child = 2 * parent + 1;}elsebreak;}}void Adjustup(int child){Compare com;int parent = (child - 1) / 2;while (child > 0){if (com(_con[parent],_con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 2) / 2;}else{break;}}}public:priority_queue(){}template<class InputIterator>priority_queue(InputIterator first, InputIterator last){while (first != last){_con.push_back(*first);first++;}//建堆for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--){Adjustdown(i);}}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();Adjustdown(0);}void push(const T& x){_con.push_back(x);Adjustup(_con.size() - 1);}const T& top(){return _con[0];}bool empty(){return _con.empty();}size_t size(){return _con.size();}private:Container _con;};

反向迭代器

顾名思义是用于反向遍历的工具。反向迭代器通常通过容器的 rbegin() 和 rend() 方法获取。rbegin() 返回指向容器最后一个元素下一个位置的反向迭代器(end),而 rend() 返回指向容器第一个元素的反向迭代器(begin)。

namespace ee
{template<class Iterator,class ref,class ptr>struct ReverseIterator{typedef ReverseIterator<Iterator, ref, ptr> self;Iterator _it;ReverseIterator(Iterator it):_it(it){ }ref operator*(){Iterator tmp = _it;return *(--tmp);}ptr operator->(){//返回解引用对象的地址return &(operator*());}self& operator++()//前置++{--_it;return *this;}self& operator--(){++_it;return *this;}bool operator!=(const self& s)const{return _it != s._it;}};
}

一般采用镜像对称的方式来模拟实现,即rbegin对应end,rend对应begin。
在重载*运算符时需要注意解引用的是迭代器当前指向的前一个位置,因为rbegin是最后元素的下一个位置,有可能为空会造成非法访问,或者是哨兵位头节点的位置。
++和–分别实现自减和自增的操作来满足反向迭代器的功能。

若不使用镜像对称的方式来模拟实现反向迭代器,那么*操作符的重载就要跟随发生变化。

vector中适配

记得包含ReverseIterator.h头文件即可

在这里插入图片描述
在这里插入图片描述

list中适配

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

mysql镜像创建docker容器,及其可能遇到的问题

前提&#xff0c;已经弄好基本的docker服务了。 一、基本流程 1、目录准备 我自己的资料喜欢放在 /data 目录下&#xff0c;所以老规矩&#xff1a; 先进入 /data 目录&#xff1a; cd /data 创建 mysql 目录&#xff1a; mkdir mysql 2、镜像查找 docker search hub.ra…

快速记忆法,提高知识点背诵效率

战国七雄&#xff1a;齐秦 韩赵魏 燕楚 谐音记忆&#xff1a;齐秦 喊赵薇 演出 五等爵位&#xff1a;公侯 伯子 男 记忆方法&#xff1a;公猴 脖子 蓝 安卓应用&#xff1a;记忆宫殿APP 记忆 脑力训练&#xff0c;中小学各学科知识点速记&#xff0c;单词趣味记忆&#xff0c…

从零开始学java--泛型(1)

泛型 学生成绩可能是数字类型&#xff0c;也可能是字符串类型&#xff0c;如何存放可能出现的两种类型呢&#xff1a; public class Score {String name;String id;Object value; //因为Object是所有类型的父类&#xff0c;因此既可以存放Integer也能存放Stringpublic Score…

pdf转latex

Doc2X&#xff08;https://doc2x.noedgeai.com/&#xff09; Doc2X 是一个由 NoEdgeAI 提供的在线工具&#xff0c;主要用于将 PDF 文件&#xff08;尤其是学术论文、报告等文档&#xff09;转换为 LaTeX 格式。LaTeX 是一种高质量排版系统&#xff0c;广泛应用于学术界和出版…

Visual Studio 2022 UI机器学习训练模块

VS你还是太超标了&#xff0c;现在机器学习都不用写代码了吗&#xff01;&#xff01; 右键项目解决方案&#xff0c;选择机器学习模型

无公网实体服务器加装多个操作系统供多个用户互不打扰使用_part1

背景介绍 因笔者业务需求&#xff0c;入手了一个实体服务器&#xff0c;但为了避免出现在一个操作系统中搭建编程环境后有许多相关的进程和服务&#xff0c;拖慢日常的使用&#xff0c;也能让其他人短期使用&#xff0c;更好的利用服务器的性能&#xff0c;让服务器专注于“什…

运动规划实战案例 | 基于四叉树分解的路径规划(附ROS C++/Python仿真)

目录 1 为什么需要四叉树&#xff1f;2 基于四叉树的路径规划2.1 分层抽象2.2 路图搜索2.3 动态剪枝 3 算法仿真3.1 ROS C算法仿真3.2 Python算法仿真 1 为什么需要四叉树&#xff1f; 路径规划的本质是在给定环境中寻找从起点到终点的最优或可行路径&#xff0c;其核心挑战在…

docker快捷打包脚本(ai版)

直接进入主题&#xff1a; 用这个脚本前提是你本地可以拉镜像仓库的镜像&#xff0c;并且在 本地有了&#xff0c;然后将所有的镜像tag写在一个文件中&#xff0c;和下面docker_tags.txt 对应&#xff0c;文件叫什么&#xff0c;脚本里对应改什么&#xff0c;给小白说的 #!/bi…

WinMerge下载及使用教程(附安装包)

文章目录 一、WinMerge安装步骤1.WinMerge下载&#xff1a;2.解压&#xff1a;3.启动&#xff1a; 二、WinMerge使用步骤1.添加文件或文件夹2.查看差异3.格式选择 WinMerge v2.16.36 是一款免费开源的文件与文件夹比较、合并工具&#xff0c;能帮您快速找出差异&#xff0c;提高…

Jmeter性能测试之生成测试报告

结构 测试计划 测试计划是顶级的层级⽬录的结构&#xff0c; 那么在这样的⽬录结构中&#xff0c;⾥⾯可以包含很多线程组 线程组 线程组我们可以简单的理解为postman测试⼯具⾥⾯的collection&#xff0c;那么在整体线程组⾥⾯&#xff0c;可以添加很多的测试 ⽤例 简单控…

CSS中的inline-flex与flex的区别

在CSS中&#xff0c;flex 和 inline-flex 都是用于实现弹性布局&#xff08;Flexbox&#xff09;的显示属性&#xff0c;但它们在布局行为上有所不同。 flex 属性会使元素表现为块级弹性容器&#xff0c;这意味着元素会在页面上占据一整行的空间&#xff0c;无论其内部内容的大…

Linux的那些基础常用命令汇总

目录 前言&#xff1a; 用户命令&#xff1a; 管理后台作业命令&#xff1a; 文件目录操作命令&#xff1a; 运维高频使用命令&#xff1a; 磁盘管理以及文件系统命令: 用户、组操作命令&#xff1a; 权限控制命令&#xff1a; 网络配置命令&#xff1a; 软件管理命令…

高效深度学习lecture03

lecture_03 **剪枝&#xff1a;**pruning basically turns a dense neural network into a sparse neural network. you can remove those redundant synapses, and also you can remove those redundant neurons. 剪枝的本质上是将稠密的神经网络转变成稀疏的神经网络&#…

Nextjs15 实战 - React Notes 项目初始化

current branch 对应如下文档 redis ioredis 本专栏内容均可在Github&#xff1a;notes_01 找到 一、效果 完整项目使用技术栈&#xff1a; Nextjs15 MySQL Redis Auth Prisma i18n strapi Docker vercel 二、修改根布局和其他页面 修改 app/page.tsx&#xff1a…

Flutter PopupMenuButton 深度解析:从入门到架构级实战

在移动应用交互设计中&#xff0c;上下文菜单如同隐形的魔法师&#xff0c;在有限屏幕空间中优雅地扩展操作维度。作为Flutter框架中的核心交互组件&#xff0c;PopupMenuButton绝非简单的菜单触发器&#xff0c;其背后蕴含着Material Design的交互哲学、声明式UI的架构智慧以及…

C++——清明

#include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> #include <sstream> #include <vector> #include <memory> #include <ctime>using namespace std;class Weapon; // 前置声明class Hero{ pr…

es --- 集群数据迁移

目录 1、需求2、工具elasticdump2.1 mac安装问题解决 2.2 elasticdump文档 3、迁移 1、需求 迁移部分新集群没有的索引和数据 2、工具elasticdump Elasticdump 的工作原理是将输入发送到输出 。两者都可以是 elasticsearch URL 或 File 2.1 mac安装 前置&#xff1a;已经安装…

鸿蒙开发_ARKTS快速入门_语法说明_组件声明_组件手册查看---纯血鸿蒙HarmonyOS5.0工作笔记010

然后我们来看如何使用组件 可以看到组件的组成 可以看到我们使用的组件 然后看一下组件的语法.组件中可以使用子组件. 然后组件中可以有参数,来修改组件的样式等 可以看到{},这种方式可以设置组件参数,当然在下面. 的方式也可以的 然后再来

【GEE学习笔记】报错解决:Sentinel-2 数据集分为 L1C(大气顶层)和 L2A(地表反射率),如何选择波段进行去云处理?

【GEE学习笔记】报错解决&#xff1a;Sentinel-2 数据集分为 L1C&#xff08;大气顶层&#xff09;和 L2A&#xff08;地表反射率&#xff09;&#xff0c;如何选择波段进行去云处理&#xff1f; 【GEE学习笔记】报错解决&#xff1a;Sentinel-2 数据集分为 L1C&#xff08;大…

OpenVLA-OFT——微调VLA时加快推理的三大关键设计:支持动作分块的并行解码、连续动作表示以及L1回归(含输入灵活化及对指令遵循的加强)

前言 25年3.26日&#xff0c;这是一个值得纪念的日子&#xff0c;这一天&#xff0c;我司「七月在线」的定位正式升级为了&#xff1a;具身智能的场景落地与定制开发商 &#xff0c;后续则从定制开发 逐步过渡到 标准产品化 比如25年q2起&#xff0c;在定制开发之外&#xff0…