【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,一经查实,立即删除!

相关文章

笔记:NodeJS electron 打包时 ETIMEDOUT

第一个方法 如果是用 npm&#xff0c;在你的 cmd 中输入 npm config set ELECTRON_MIRROR https://npmmirror.com/mirrors/electron/如果用 yarn&#xff0c;就输入 yarn config set electron_mirror https://npmmirror.com/mirrors/electron/第二个方法 如果第一个方法不行…

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

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

深入探究 SOCKS5 代理:加强网络安全与高效爬虫的利器

一、 SOCKS5 协议简介 SOCKS5&#xff08;Socket Secure 5&#xff09;是 SOCKS 协议的最新版本&#xff0c;它允许客户端向代理服务器发送请求&#xff0c;并将数据传输到目标服务器。相比于旧版 SOCKS 协议&#xff0c;SOCKS5 提供了更强大的身份验证机制和数据加密功能&…

分表后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. 图中点的层次 相关链接 要学会建树、建图的通用方法。…

s390x 架构docker安装mysql

由于 MySQL 官方未提供 s390x 架构镜像&#xff0c;所以在应用商店启用 MySQL 前&#xff0c;需要手动修改 MySQL 镜像版本 MySQL 5.7 下载 s390x 架构最新版本镜像 docker pull ibmcom/mysql-s390x:5.7.34将镜像重命名为 1Panel 应用商店中使用的 MySQL 版本 docker tag i…

逻辑回归概述

逻辑回归介绍 1. 逻辑回归的应用场景 逻辑回归(Logistic Regression)是机器学习中的 一种分类模型 ,逻辑回归是一种分类算法,虽然名字中带有回归。由于算法的简单和高效,在实际中应用非常广泛 广告点击率是否为垃圾邮件是否患病信用卡账单是否会违约 逻辑回归就是解决二…

【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…

org.springframework.web.client.RestTemplate 的使用

目录 前言使用配置具体使用 前言 后端难免会发送请求&#xff0c;大致分为两种请求&#xff1a;微服务之间的内部请求和系统之间的外部请求&#xff0c;org.springframework.web.client.RestTemplate对这两种请求都支持。 使用 配置 import org.springframework.cloud.clie…

为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 为什么存在内…

使用Kafka Streams开发流处理应用

使用Kafka Streams开发流处理应用 一、简介1.1 Kafka Streams定义1.2 Kafka Streams的优势1.3 Kafka Streams应用场景 二、环境搭建2.1 安装Kafka2.2 安装Kafka Streams2.3 构建Kafka集群 三、Kafka Streams编程API介绍3.1 Kafka Streams主要API3.2 应用程序的配置和参数3.3 To…

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…

分布式 - 负载均衡Nginx:Nginx常见问题总结(一)

文章目录 01. 什么是Nginx&#xff1f;02. 为什么要用Nginx?03. 为什么Nginx性能这么高&#xff1f;04. Nginx 为什么不使用多线程&#xff1f;05. Nginx 请求处理流程是什么&#xff1f;06. Nginx怎么处理请求的&#xff1f;07. 什么是正向代理和反向代理&#xff1f;08. 反向…

Python爬虫学习笔记(七)————Selenium

目录 1.什么是selenium&#xff1f; 2.为什么使用selenium&#xff1f; 3.selenium安装 4.selenium的使用步骤 5.selenium的元素定位 6.访问元素信息 7.交互 1.什么是selenium&#xff1f; &#xff08;1&#xff09;Selenium是一个用于Web应用程序测试的工具。 &#…