【C++进阶之路】适配器、反向迭代器、仿函数

文章目录

  • 前言
  • 一、适配器
    • ①模拟实现栈
    • ②模拟实现对列
  • 二、反向迭代器
  • 三、仿函数
  • 总结

前言

我们先来笼统的介绍一下今天的三个内容。

  • 适配器——简单的理解就是复用,用已经实现的轮子,来继续实现某种功能。

  • 反向迭代器——原理很简单,就是对称+复用(已经造好的正向迭代器)

  • 仿函数——与函数用法相同的类,用于排序,比如大堆,小堆,升序,降序。

一、适配器

适配器的功能,在我们模拟实现栈和对列时十分方便!
先用这两个例子感受一下。

①模拟实现栈

	template<class T,class Con = deque<T>>class stack{public:void push(const T& val){st.push_back(val);}void pop(){st.pop_back();}T& top(){return st[st.size() - 1];}size_t size(){return st.size();}bool empty(){return st.empty();}private:Con st;};

②模拟实现对列

	template<class T, class Con = deque<T>>class queue{public:void push(const T& val){qu.push_back(val);}void pop(){qu.pop_front();}T& front(){return qu[0];}size_t size(){return qu.size();}bool empty(){return qu.empty();}private:Con qu;};

这里的模板参数:

template<class T, class Con = deque<T>>//这就是适配器

看完这两个例子,你可能会明白,并且可能会惊讶于适配器的方便之处。

并且这里也给了模板一个用法——缺省参数

且如果是全缺省的话,我们示例化还是要给参数列表的。

如下:

stack<> st;

再来谈谈deque,你可能会好奇,这里在栈的第二个缺省参数为啥不给vector<T>, 对列的第二个缺省参数为啥不给list<T>

要弄清楚原因我们先得了解deque的基本结构:

在这里插入图片描述

我们知道这个中控数组一旦满了,就要考虑扩容的问题,那该如何扩呢?

只需要将中控数组进行扩容,然后将指针拷贝过去即可。

因此相较于vector无需动数据即可完成扩容!—— 提高了扩容的效率

相较于vector,这种结构也支持随机访问,不过得通过计算,这样高频率的随机访问效率会降低,缓冲命中率也有一定的下降。

相较于list,由于list是单个申请单个释放,因此deque的缓冲命中率较高。

但是相较于list,如果deque要在中间插入数据,那效率就会降低,这一点不如list。

这样:

  1. stack结构,实现尾插尾删功能,如果要考虑扩容的效率,deque的优势更大。
  2. queue结构,实现尾插头删功能,如果要考虑到缓冲命中率,deque的优势更大。

因此库里采用了deque来实现栈和对列!

二、反向迭代器

我们先来看库里的实现方式:

  • vector
    在这里插入图片描述
  • list
    在这里插入图片描述

可以看到,这里呈现对称的方式,但是如何解引用是关键

库里是这样实现的:

Reverse_iterator operator* ()
{Iterator tmp(_it);return *--tmp;
}

这里使用了正向迭代器的拷贝构造,然后再减减访问反向迭代器的下一个元素,这样实现了错位,也能刚好利用实现好的正向迭代器。

剩余的就不难实现了:

	template<class Iterator, class Ref, class Ptr>struct Reverse_iterator{typedef Reverse_iterator<Iterator, Ref, Ptr> self;//自定义的类型不能被当做类名进行使用Reverse_iterator(const Iterator& it){_it = it;}self& operator ++(){_it--;return *this;}self operator ++(int){self tmp(_it);_it--;return self;}Ref operator* (){Iterator tmp(_it);return *--tmp;}Ptr operator->(){return _it.operator->();}bool operator!=(const Reverse_iterator&it)const{return _it != it._it;}bool operator==(const Reverse_iterator& it)const{return _it == it._it;}Iterator _it;};

然后我们只需在容器里加上下面的代码即可完成复用!

		typedef list_iterator<T,T&,T*> iterator;typedef list_iterator<T,const T&,const T*> const_iterator;typedef Reverse_iterator<iterator, T, T*> reverse_iterator;typedef Reverse_iterator <const_iterator, const T, const T*>\const_reverse_iterator;reverse_iterator rbegin(){return end();//这里会调用拷贝构造}reverse_iterator rend(){return begin();}

三、仿函数

我们这里先实现一个优先级对列——大堆。

	template<class T,class Container = vector<T>>class priority_queue{//建大堆void AdjustDown(int parent){//假设左孩子较大size_t child = parent * 2 + 1;//因为是往下比较,所以child应在范围内while (child < con.size()){//先选出来较大的孩子,当然前提得存在。if (child + 1 < con.size() && con[child] < con[child + 1]){child = child + 1;}//再跟父节点进行比较,如果孩子大就换if (con[parent]< con[child]){swap(con[parent], con[child]);//因为是向下比较的,所以要看parent是不是还比下面的孩子大。parent = child;child = parent * 2 + 1;}else{break;}}}//建大堆void AdjustUp(int child){int parent = (child - 1) / 2;while (parent >= 0){if (con[parent] < con[child]){swap(con[parent], con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}public:template<class InputIterator>priority_queue(InputIterator first, InputIterator last){InputIterator it = first;while (it != last){con.push_back(*it);it++;}//进行调堆//从最后一个叶子结点的父节点开始。//时间复杂度O(N)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& val){con.push_back(val);AdjustUp(con.size() - 1);}size_t size(){return con.size();}bool empty(){return con.empty();}T top()const{return con[0];}priority_queue(){}private:Container con;};

这里的大堆算是实现了,借助这二叉树的一点点知识。

  • 那如果我们还要实现小堆呢?

用不用cv一份,再改呢?其实不用,只需要写一个仿函数即可。

	template<class T>struct Less{bool operator()(const T &x1 ,const T& x2){return x1 < x2;}};template<class T>struct Greater{bool operator()(const T& x1, const T& x2){return x1 > x2;}};

如何使用呢?用类模板+重载函数的掉用。

template<class T,class Container = vector<T>,class Compare = Less<T>>
class priority_queue
{//建大堆void AdjustDown(int parent){//假设左孩子较大size_t child = parent * 2 + 1;//因为是往下比较,所以child应在范围内while (child < con.size()){//先选出来较大的孩子,当然前提得存在。if (child + 1 < con.size() && com(con[child] , con[child + 1])){child = child + 1;}//再跟父节点进行比较,如果孩子大就换if (com(con[parent], con[child])){swap(con[parent], con[child]);//因为是向下比较的,所以要看parent是不是还比下面的孩子大。parent = child;child = parent * 2 + 1;}else{break;}}}//建大堆void AdjustUp(int child){int parent = (child - 1) / 2;while (parent >= 0){if (com(con[parent] , con[child])){std::swap(con[parent], con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}
public:template<class InputIterator>priority_queue(InputIterator first, InputIterator last){InputIterator it = first;while (it != last){con.push_back(*it);it++;}//进行调堆//从最后一个叶子结点的父节点开始。//时间复杂度O(N)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& val){con.push_back(val);AdjustUp(con.size() - 1);}size_t size(){return con.size();}bool empty(){return con.empty();}T top()const{return con[0];}priority_queue(){}
private:Container con;Compare com;
};

这样既可以当做大堆使用,也可以当做小堆使用。

总结

 今天的分享就到这里了,如果觉得文章不错,点个赞鼓励一下吧!我们下篇文章再见

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

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

相关文章

摄影测量-共线方程、共面方程

1、共线方程 在摄影测量中&#xff0c;绝大多数的结算方法都是基于共线条件方程式的&#xff0c;如单片空间后方交会解法、像对空间前方交会解法、光束法区域网评查以及直接线性变换等。 2、共面方程 描述像片对内摄影基线以及同名光线位于同一平面的一种条件方程。在摄影测量…

分表后mybatis-plus删除操作失效等问题处理

因为重构dao层&#xff0c;问题太多了&#xff0c;于是想着另起一个章节。 4 count的问题 使用count复用&#xff0c;不需要查询所有字段&#xff0c;否则会出现下面的错误 ### SQL: SELECT COUNT( t.id,t.company_id,t.user_id,t.bind_time,t.role_type,t.job_type,t.studen…

openSUSE leap 15.3安装mysql-community-server

openSUSE Software 下载"https://software.opensuse.org/ymp/home:bjoernv/15.3/mysql-community-server.ymp" wget "https://software.opensuse.org/ymp/home:bjoernv/15.3/mysql-community-server.ymp" 双击"mysql-community-server.ymp" 添…

【算法基础:搜索与图论】3.2 树与图的dfs和bfs

文章目录 例题846. 树的重心&#xff08;深度优先遍历 / 树形DP&#xff09;⭐⭐⭐⭐⭐&#x1f6b9;&#x1f6b9;&#x1f6b9;&#x1f6b9;&#x1f6b9;&#xff08;重要&#xff01;好题&#xff01;&#xff09;847. 图中点的层次 相关链接 要学会建树、建图的通用方法。…

【Matlab】基于遗传算法优化 BP 神经网络的数据回归预测(Excel可直接替换数据)

【Matlab】基于遗传算法优化 BP 神经网络的数据回归预测&#xff08;Excel可直接替换数据&#xff09; 1.模型原理2.文件结构3.Excel数据4.分块代码4.1 arithXover.m4.2 delta.m4.3 ga.m4.4 gabpEval.m4.5 initializega.m4.6 maxGenTerm.m4.7 nonUnifMutation.m4.8 normGeomSel…

为harbor仓库添加https,新增DigiCert 免费版SSL证书

完成效果&#xff1a; 前言&#xff1a;在本地搭建好docker的镜像仓库harbor后&#xff0c;当我们登录docker login时&#xff0c;会提示证书问题x509: cannot validate certificate 登录本地报错X509 无法登录仓库也无法上传和拉取镜像&#xff0c;虽然有本机的解决方法&…

300M的联通宽带,电脑直接连接光猫只有100M;电脑连接路由器,然后路由器连接光猫却有300M???

1. 现象 300M的联通宽带&#xff0c;用了小半年之后发现网络比以前满&#xff0c;通过https://www.speedtest.cn网站测试发现只有100M 2. 猜测 难道是联通这帮人&#xff0c;偷偷把我网速降到了100M&#xff1f;&#xff1f;&#xff1f; 3. 排查过程 打电话让联通师傅上门排查…

Windows下YUICompress实现js、css混淆压缩

首先&#xff0c;我们针对Linux下的部分命令进行Windows系统的对应实现 ls————cmd /c dir/b rm————cmd /c del mv————cmd /c move pwd————cmd /c chdir 注&#xff1a;cmd /c是执行完命令后关闭命令行窗口、cmd /k是执行完命令后不关闭命令行窗口、cmd /c sta…

归并排序与计数排序

目录 一、归并排序 1.基本思想 2.归并排序的特性总结&#xff1a; 3.代码实现&#xff1a; 4.代码优化 &#xff1a; 二、计数排序&#xff08;非比较排序&#xff09; 1. 概念&#xff1a; 2.计数排序的特性总结&#xff1a; 3.代码实现&#xff1a; 一、归并排序 1.…

香农极限是如何影响光纤容量的

1 引言 上世纪末&#xff0c;DWDM技术开始在干线通信中使用并迅速普及。虽然当时DWDM系统的容量只有402.5G&#xff0c;但实验室中DWDM支持的波道数甚至超过了1000波&#xff0c;单波道速率也飙到了惊人的160G&#xff08;超1000波和单波160G是两个独立事件&#xff09;。人们普…

自定义类型:结构体进阶学习分享

自定义类型&#xff1a;结构体进阶学习分享 前言1 结构体的基础知识2 结构的声明3 特殊声明4 结构的自引用5 结构体变量的定义和初始化6 结构体内存对齐6.1 计算结构体大小相关笔试题&#xff08;基于VS&#xff09;笔试题一&#xff1a;笔试题二&#xff1a; 6.2 为什么存在内…

FFmpeg 命令行实现居中高清上下模糊播放效果

FFmpeg 命令行实现居中高清上下模糊播放效果。 1、16:9 的横屏原视频&#xff0c;以 16:9 竖屏上下模糊播放 以该效果播放视频的命令如下&#xff1a; ffplay -i horizontal_test_video_169.mp4 -vf \ "split[a][b]; \ [a]crop(ih/16*9):ih,scaleiw/10:-1,gblursigma5…

深度理解 Spring AOP

一、什么是AOP(面向切面编程)&#xff1f;&#x1f349; AOP 为 Aspect Oriented Programming 的缩写&#xff0c;意思为面向切面编程&#xff0c;是通过预编译方式 和运行期 动态代理 实现程序功能的统一维护的一种技术。 AOP &#xff08;面向切面编程&#xff09;是 OOP&a…

代码随想录额外题目| 数组02 ●189旋转数组 ●724寻找数组中心索引

#189旋转数组 很快写出来但是用了个新数组&#xff0c;不好 void rotate(vector<int>& nums, int k) {vector<int> res(nums.size(),0);for(int i0;i<nums.size();i){int newiik;if(newi>nums.size()-1) newinewi%nums.size();res[newi]nums[i];}numsr…

vue组件(个人学习笔记三)

目录 友情提醒第一章、vue的组件1.1&#xff09;什么是SPA应用1.2&#xff09;vue的组件简介1.3&#xff09;vue工程中的main.js文件 第二章、Vue组件的使用2.1&#xff09;一般组件的自定义2.2&#xff09;注册组件&#xff1a;全局注册和局部注册2.2.1&#xff09;全局注册&a…

和chatgpt学架构04-路由开发

目录 1 什么是路由2 如何设置路由2.1 安装依赖2.2 创建路由文件2.3 创建首页2.4 编写HomePage2.5 更新路由配置2.6 让路由生效 3 测试总结 要想使用vue实现页面的灵活跳转&#xff0c;其中路由配置是必不可少的&#xff0c;我们在做开发的时候&#xff0c;先需要了解知识点&…

Vue--》打造个性化医疗服务的医院预约系统(二)

今天开始使用 vue3 + ts 搭建一个医院预约系统的前台页面,因为文章会将项目的每一个地方代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的GithHub上,大家可以自行去进行下载运行,希望本文章对有帮助的朋友们能多多关…

基于Python+多层RNN+Tensorflow藏头诗与歌词智能生成-深度学习算法应用(含全部工程源码)+训练数据集

目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境Tensorflow 环境PyCharm环境 模块实现古诗生成1. 数据预处理2. 模型构建3. 模型训练及保存4. 使用模型生成古诗5. 产生藏头诗6. 用词云展示生成的古诗 歌词生成1. 数据预处理2. 模型构建3. 模型训练并保存4. 生成…

基于Kitti数据集的智能驾驶目标检测系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于Kitti数据集的智能驾驶目标检测系统可用于日常生活中检测与定位行人&#xff08;Pedestrian&#xff09;、面包车&#xff08;Van&#xff09;、坐着的人&#xff08;Person Sitting&#xff09;、汽车&#xff08;Car&#xff09;、卡车&#xff08;Truck…

【字符流】案例:文件到集合

案例&#xff1a;文件到集合 1.需求&#xff1a; 把文本文件中的数据读取到集合&#xff0c;并遍历集合。要求&#xff1a;文件中的每一行数据是一个集合元素 2.思路 创建字符缓冲输入流对象创建ArrayList集合对象调用字符缓冲输入流对象的方法读数据把读取到的字符串数据存…