实现优先队列——C++

目录

1.优先队列的类模板

2.仿函数的讲解

3.成员变量

4.构造函数

5。判空,返回size,返回队头

6.插入

7.删除


1.优先队列的类模板

我们先通过模板来进行初步了解

由上图可知,我们的模板里有三个参数,第一个参数自然就是你要存储的数据的类型了;第二个参数是我们的适配器,适配器可以手动更改,但我们这里就用它默认的vector,这就意味着我们的优先队列是由我们的顺序表容器来实现的;第三个参数是我们的仿函数,仿函数是我们这个优先队列的重要知识点,等会我会详细说明。

我先把代码全放出来,这样方便不理解的时候可以看到全部代码来思考。

我提前说明一下,优先队列的本质其实就是vector和堆的性质。

template<class T>class less{public:bool operator()(const T& a, const T& b){return a < b;}};template<class T>class greater{public:bool operator()(const T& a, const T& b){return a > b;}};template<class T,class Container=vector<T>,class comper=less<T>>class priority_queue{public://构造priority_queue(){}//拷贝构造//模板函数//迭代器版template <class InputIterator>priority_queue(InputIterator first, InputIterator last){while (first != last){push(*first);first++;}}//判空bool empty() const{return _con.empty();}//返回sizesize_t size() const{return _con.size();}//返回队头const T& top(){return _con[0];}//插入//向上调整void adjustup(size_t child){size_t parent = (child - 1) / 2;while (child > 0){if (cmp(_con[parent], _con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}elsebreak;}}void push(const T& x){_con.push_back(x);adjustup(_con.size()-1);}//删除//向下调整void adjustdown(size_t parent){size_t child = parent * 2 + 1;while (child < _con.size()){if (child+1<_con.size() && cmp(_con[child], _con[child+1])){child++;}if (cmp(_con[parent], _con[child])){swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}elsebreak;}}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjustdown(0);}private:Container _con;comper cmp;};

2.仿函数的讲解

仿函数是什么意思呢,我们不妨猜测一下,通过它的名字,仿函数似乎是一个模仿函数的存在,这个猜测其实就是对的。仿函数没有什么门道,它的底层就是进行了一个运算符重载,重载的是(),所以调用的时候感觉像是在调用函数一样。

template<class T>class less{public:bool operator()(const T& a, const T& b){return a < b;}};

我们可以通过上面的代码发现我们的类叫less,里面重载了一个()运算符,使其能达到判断较小值的目的;

template<class T>class greater{public:bool operator()(const T& a, const T& b){return a > b;}};

有了判断较小值,自然就有判断较大值,原理也是跟上面一样。

有了仿函数我们就能更加方便且安全的对自定义类型的数据进行有意义的大小比较。

3.成员变量

private:Container _con;comper cmp;

成员变量我们自然还是设置成私有的,这两个成员变量的类型是不是有一点懵逼?其实是我们的类模板声明的。

template<class T,class Container=vector<T>,class comper=less<T>>

所以我们的第一个成员变量的类型是我们的vector,第二个是我们的仿函数类型的数据。

4.构造函数

//构造priority_queue(){}

其实我们仔细想一想就能明白,我们的优先队列的底层既然是vector和堆,而我们的优先队列存在的意义就像是给vector再加工一下,实现堆的性质和功能,所以我们的优先队列甚至不需要自己实现构造函数,直接让它自动调用vector的就行了。析构函数也是一样的道理,我们既然不需要写构造函数,那么析构函数直接不定义了,调用系统默认的就可以了。

5。判空,返回size,返回队头

//判空bool empty() const{return _con.empty();}//返回sizesize_t size() const{return _con.size();}//返回队头const T& top(){return _con[0];}

这三个功能真的没有什么好解释的,大家一看就能理解,这不都是复用了vector的功能嘛。

6.插入

//插入//向上调整void adjustup(size_t child){size_t parent = (child - 1) / 2;while (child > 0){if (cmp(_con[parent], _con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}elsebreak;}}void push(const T& x){_con.push_back(x);adjustup(_con.size()-1);}

插入功能就是这个优先队列不同于顺序表的地方之一了,因为是堆的性质,所以我们插入的时候肯定不能单纯的插入,我们要进行向上调整,向上调整的目的就是把我们的vector打造成堆的模样。我们就来讲解一下向上调整

我们这次建的是大堆,大堆是什么意思呢?大堆就是我们的父亲节点要大于我们的孩子节点,所以如果我们的父亲节点小于孩子节点我们就交换父亲节点和孩子节点的值。

仿函数的用法就出现了

cmp(_con[parent], _con[child])

不说的话大家是不是就以为cmp是我们的普通函数了?仿函数的妙用就在这里。

然后我再说明一下,孩子节点和父亲节点是如何来确定的,我们知道顺序表的物理结构也是连续的,下标从0开始,我们的父亲节点只需要*2加1就能找到左孩子,再加一就能找到右孩子,而我们的不管是左孩子还是右孩子都只需要-1再除2就能找到父亲了,这其中的数学原理大家下去画画图,很快就能得出这个结论了。

7.删除

//删除//向下调整void adjustdown(size_t parent){size_t child = parent * 2 + 1;while (child < _con.size()){if (child+1<_con.size() && cmp(_con[child], _con[child+1])){child++;}if (cmp(_con[parent], _con[child])){swap(_con[parent], _con[child]);parent = child;child = parent * 2 + 1;}elsebreak;}}void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjustdown(0);}

删除用的就是我们的向下调整了。我们的优先队列的数据是连续的,从头部删除性能肯定不好,所以我们的思路是先把要删除的元素跟最后一个交换,然后删除最后一个元素就能达到我们的效果了,这个时候为了保证我们堆的性质要对首元素进行调整,调整到它该去的位置。

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

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

相关文章

使用Android Studio 搭建AOSP FrameWork 源码阅读开发环境

文章目录 概述安装Android Studio编译源码使用Android Studio打开源码制作ipr文件直接编译成功后自动打开Android Studio 修改SystemUI验证开发环境 概述 我们都知道Android的系统源码量非常之大&#xff0c;大致有frameworka层源码&#xff0c;硬件层(HAL)源码&#xff0c;内…

Java高阶私房菜:JVM分代收集算法介绍和各垃圾收集器原理分解

目录 什么是分代收集算法 GC的分类和专业术语 什么是垃圾收集器 垃圾收集器的分类及组合 ​编辑 应关注的核心指标 Serial和ParNew收集器原理 Serial收集器 ParNew收集器 Parallel和CMS收集器原理 Parallel 收集器 CMS收集器 新一代垃圾收集器G1和ZGC G1垃圾收集器…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 5月3日,星期五

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年5月3日 星期五 农历三月廿五 1、 气象台&#xff1a;我国南方地区3至5日将出现新一轮较强降水&#xff0c;局地有大暴雨。 2、 广东11地市打破4月雨量历史记录&#xff1a;梅州平均雨量为常年3.5倍。 3、 梅大高速路面塌…

Redis学习笔记(基础)

Redis学习笔记&#xff08;基础&#xff09; 一、Nosql概述1.1、为什么使用Nosql1.2、什么是Nosql1.3、阿里巴巴演进分析1.4、NoSQL的四大分类 二、 Redis入门2.1、概述2.2、Windows使用Redis2.3、linux安装2.4、redis-benchmark性能测试2.5、Redis基础知识 三、五大数据类型3.…

NIO(非阻塞I/O)和IO(阻塞I/O)详解

文章目录 一、NIO&#xff08;Non-blocking I/O&#xff0c;非阻塞I/O&#xff09;1、Channel&#xff08;通道&#xff09;与Buffer&#xff08;缓冲区&#xff09;1.1、使用ByteBuffer读取文件1.2、ByteBuffer 方法1.2、ByteBuffer 结构1.3、字符串与 ByteBuffer 互转1.4 Sca…

自然语言处理 (NLP) 中的迁移学习

--懂王 在大数据高速发展的时代&#xff0c;AI的发展日新月异&#xff0c;充满挑战的迎接未来。 自然语言处理 (NLP) 中的迁移学习: 迁移学习在 NLP 中越来越受欢迎&#xff0c;特别是在数据稀缺的情况下。如何有效地利用预训练的语言模型&#xff0c;并将其迁移到新的任务和领…

前端框架编译器之模板编译

未经作者允许&#xff0c;禁止转载 编译原理概述 编译原理&#xff1a;是计算机科学的一个分支&#xff0c;研究如何将 高级程序语言 转换为 计算机可执行的目标代码 的技术和理论。 高级程序语言&#xff1a;Python、Java、JavaScript、TypeScript、C、C、Go 等。计算机可执…

微软开源 MS-DOS「GitHub 热点速览」

上周又是被「大模型」霸榜的一周&#xff0c;各种 AI、LLM、ChatGPT、Sora、RAG 的开源项目在 GitHub 上“争相斗艳”。这不 Meta 刚开源 Llama 3 没几天&#xff0c;苹果紧跟着就开源了手机端大模型&#xff1a;CoreNet。 GitHub 地址&#xff1a;github.com/apple/corenet 开…

golang 基础知识细节回顾

之前学习golang的速度过于快&#xff0c;部分内容有点囫囵吞枣的感觉&#xff0c;写gorm过程中有很多违反我常识的地方&#xff0c;我通过复习去修正了我之前认知错误和遗漏的地方。 itoa itoa自增的作用在编辑error code时候作用很大&#xff0c;之前编辑springboot的error c…

idea常用知识点随记

idea常用知识点随记 1. 打开idea隐藏的commit窗口2. idea中拉取Git分支代码3. idea提示代码报错&#xff0c;项目编译没有报错4. idea中实体类自动生成序列号5. idea隐藏当前分支未commit代码6. idea拉取新建分支的方法 1. 打开idea隐藏的commit窗口 idea左上角File→Settings…

前沿科技应用:AIGC技术的广泛渗透

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

基于alpha shapes的边缘点提取(matlab)

1、原理介绍 由Edelsbrunner H提出的alpha shapes算法是一种简单、有效的快速提取边界点算法。其克服了点云边界点形状影响的缺点&#xff0c;可快速准确提取边界点。如下图所示&#xff0c;对于任意形状的平面点云&#xff0c;若一个半径为a的圆&#xff0c;绕其进行滚动&…

LSTM-KDE的长短期记忆神经网络结合核密度估计多变量回归区间预测(Matlab)

LSTM-KDE的长短期记忆神经网络结合核密度估计多变量回归区间预测&#xff08;Matlab&#xff09; 目录 LSTM-KDE的长短期记忆神经网络结合核密度估计多变量回归区间预测&#xff08;Matlab&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.LSTM-KDE的长短期…

Flutter笔记:Widgets Easier组件库(5)使用加减器

Flutter笔记 Widgets Easier组件库&#xff08;5&#xff09;&#xff1a;使用加减器 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress…

机器学习:深入解析SVM的核心概念【三、核函数】

核函数 **问题一&#xff1a;为什么说是有限维就一定存在高维空间可分呢&#xff1f;**原始空间与特征空间为什么映射到高维空间可以实现可分核函数的作用 **问题二&#xff1a;最终怎么得到函数**从对偶问题到决策函数的步骤&#xff1a;结论 **问题三&#xff1a;为什么说特征…

nginx--第三方模块安装上传下载服务

第三方模块安装 准备 cd /usr/local/src/ yum install git -y git clone https://github.com/openresty/echo-nginx-module.git cd nginx-1.24.0 yum -y install perl-devel perl-ExtUtils-Embed zlib-devel gcc-c libtool openssl openssl-devel 编译安装 ./configure \--p…

ZooKeeper知识点总结及分布式锁实现

最初接触ZooKeeper是之前的一个公司的微服务项目中&#xff0c;涉及到Dubbo和ZooKeeper&#xff0c;ZooKeeper作为微服务的注册和配置中心。好了&#xff0c;开始介绍ZooKeeper了。 目录 1.ZooKeeper的基本概念 2.ZooKeeper的节点&#xff08;ZNode&#xff09; 3. ZooKeep…

机器学习之基于Tensorflow(LSTM)进行多变量时间序列预测股价

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 项目简介&#xff1a;机器学习之基于TensorFlow&#xff08;LSTM&#xff09;进行多变量时间序列预测股价 一、项目…

Python量化炒股的获取数据函数—get_fundamentals_continuously()

Python量化炒股的获取数据函数—get_fundamentals_continuously() get_fundamentals()函数只能用于查询某一交易日的股票财务数据信息&#xff0c;如果要查询多个交易日的股票财务数据信息&#xff0c;就要使用get_fundamentals_continuously()函数&#xff0c;语法格式如下&a…

Django数据库创建存储及管理

一、什么是ORM Django的ORM(Object-Relational Mapping)是Django框架中一个非常重要的组件。ORM可以让开发者以面向对象的方式操作数据库,而不需要直接编写SQL语句。 具体来说,Django ORM提供了以下功能: 模型定义:开发者可以在Django应用中定义Python类来表示数据库表,这些…