【C++】STL反向迭代器模拟实现,迭代器适配器,迭代器类型简单介绍

news2024/11/26 4:38:33

反向迭代器

    • 前言
    • 正式开始
      • 基本演示
      • 模拟实现的大致思路
      • 基本框架
      • 前置++、--
      • *重载
      • ->重载
      • list和vector适配反向迭代器
      • 迭代器的类型
      • 库中reverse和sort模板参数中的迭代器
        • reverse
        • sort

在这里插入图片描述

前言

本篇主要讲反向迭代器的模拟实现。

能够加深各位对泛型的理解。

前面我那篇string介绍里面已经提到过反向迭代器是啥了,如果点进来的同学还不知道,可以看看:[string介绍](https://blog.csdn.net/m0_62782700/article/details/130796914?
spm=1001.2014.3001.5501)

迭代器,可以在不暴露底层实现细节的情况下,提供统一的方式去访问容器。
那么其屏蔽了底层实现,体现除了C++的封装的价值。

这些专业术语,就不说那么多了,下面说人话。

正式开始

前面两篇栈和队列与优先级队列,这三个都是容器适配器,就是传什么容器,就能够用什么容器来实现其函数接口。

如果对于适配器不清楚,可以看我这两篇:
【C++】STL栈和队列基本功能介绍、题目练习和模拟实现(容器适配器)
【C++】STL优先级队列(priority_queue)功能介绍以及模拟实现

那么这一篇讲的是反向迭代器,其也是适配器,但是不是容器适配器,而是迭代器适配器,对照着上面容器适配器的话来说,就是当我们传入什么容器的正向迭代器,就生成对应的容器的反向迭代器。

是不是有点懵了,先别懵,咱们实现起来就搞清楚了。

基本演示

其实反向迭代器和正向迭代器差别是不大的。

我们先用vector演示一下正向和反向迭代器:

正向
在这里插入图片描述

反向
在这里插入图片描述

用起来就是名字上差了点区别而已。

模拟实现的大致思路

前面我那篇list模拟实现的最后也说到了,要模拟实现反向迭代器,需要在栈和队列这块学了适配器才能真正领悟到其精髓,不然吃不透。那么现在适配器已经学了,既可以说一说反向迭代器了。

对于我们普通人来说,如果我们想要实现一个反向迭代器,会怎么做?
我当时是这样想的,对于list而言,迭代器是其结点的地址,那么我可以在各个反向迭代器的接口中复用一下list迭代器的正向接口。

大致的图解是这样的:
在这里插入图片描述
那么如果是这样写的话,我们就可以用这样的思路来搞一搞。

但是库中的可不是这样实现的,库可是大佬写出来的。
大佬是怎么想的呢?

  1. list的反向迭代器搞出了,vector的反向迭代器怎么搞?
  2. 如何复用正向迭代器?
  3. 是否可以搞出来迭代器适配器?

那么我们就来根据大佬的思路搞一搞。

首先就是适配器的问题,就是第一点和第三点。
当我们传入什么容器的正向迭代器,就生成对应的容器的反向迭代器。
那么就要搞一个模板参数Iterator,这个模板参数用来接收传入的迭代器。

然后就是复用的问题。
我们就复用传入的正向迭代器,来实现我们的反向迭代器。

那么就先搭出框架。

基本框架

在这里插入图片描述
上面就复用了传入的迭代器,生成一个__reverse_iterator的成员变量_cur,但是其本质还是iterator的。这就是复用。

那么构造函数我们就要用一个Iterator的变量来给_cur赋值。
就长这样:
在这里插入图片描述
然后我们再复用Iterator的++、–、*、->等函数来实现反向的迭代器。
在这之前我们可以先把我们的当前类重命名一下,写着方便点。

在这里插入图片描述

这就是用正向的来实现反向的,不是传存储的数据类型T,而是传正向的迭代器。
因为我们定义对象的时候是直接用容器后面跟着<数据类型>,比如说list就是list<int>,数据类型T在这里就定好了。
所以其反向的迭代器就是list<int>::reverse_iterator,并不是在迭代器的后面定类型的。
而这里用迭代器定义对象的时候,也不用在reverse_iterator后面加上<Iterator>,因为我们定义list<int>的时候是先在list类内typedef正向的迭代器的,正向迭代器的模板参数就是<T, T&, T*>,只要前面T定好了,正向的迭代器就搞好了,之后才轮到我们现在写的反向迭代器的,而反向迭代器模板参数直接穿的是正向迭代器Iterator,所以说只要vector类中模板参数T定好了,那么后面的所有类型就都定好了。是不需要我们手动再传任何的模板参数的。

如果上面这段话看起来非常懵的话,可以看看我前面几篇STL容器的模拟实现。

然后就复用一下正向迭代器的几个函数接口。来实现一下反向迭代器的++、–、*、->等接口。

前置++、–

反向迭代器和正向迭代器是相反的遍历顺序,那么就可以用正向的++来实现反向的–,用正向的–来实现反向的++。
在这里插入图片描述
后置的我就不写了,各位自己练个手。

*重载

*,就是解引用,返回的值能修改,那么返回引用即可,但是我们这里模板参数没有传数据类型T,不知道怎么搞定这个返回值。那么有两种做法,一个是萃取,非常麻烦,本人能力有限,搞不定。二个就是再写下模板参数即可。
那我当然选第二个了,更轻松一点,但是后面还有->重载,我们加上两个模板参数,一个引用,一个指针。

在这里插入图片描述
然后记得改内部的那个typedef:
在这里插入图片描述

写一下*重载:
在这里插入图片描述

->重载

我在list实现中,也写过这个:
在这里插入图片描述
看不懂的话,我只能说看一下我的这篇实现:【C++】手把手教你模拟实现list的基本功能

其实不用往下写了。
上面的模拟实现和库中的是不一样的。
为什么呢?
因为我们从图解那里就和库中的不一样。
我们来看一看库中的*和->重载是啥:
在这里插入图片描述
可以看到,*重载返回的是cur - 1。

再来看一下list库中的rbegin和rend:
在这里插入图片描述
不知道各位能看出来啥不?
就是rbegin是end,rend是begin。

那么对应到图解中就是这样的:
在这里插入图片描述
而我们画的图解是这样的:
在这里插入图片描述
所以问题就出现了。

我们就可以把我们的*和->改一改。
其实改*就好。
在这里插入图片描述
由于我的list模拟里没有实现减法重载,但实现–了,就凑合一下,也能用。

然后再实现以下 !=反向的迭代器就能用了。
在这里插入图片描述

list和vector适配反向迭代器

我们用list模拟的代码来用一用这里的反向迭代器,在我们的list迭代器中,搞出来反向迭代器和rbegin、rend。记得在list中引用一下我们反向迭代器的头文件。

在这里插入图片描述

rbegin和rend:

在这里插入图片描述

然后来测试一下:

在这里插入图片描述

list实现了,我们也用vector实现一下,同样,也是要在vector头文件中typedef一下反向迭代器并实现rbegin和rend。

代码typedef的代码、rbegin、rend的代码和list一模一样,我就不写了。

测试一下:
在这里插入图片描述
完全是OK的。

那么到这里迭代器适配器就讲完了。
上面用了list和vector的正向迭代器两个例子来适配出了各自的反向迭代器。很成功。

那么问题来了:只要有正向迭代器就能适配出反向迭代器吗?
答案是错误的。要有条件,必须能够支持++和–。但最主要的还是–。

迭代器的类型

我们来看一下所有的容器:
在这里插入图片描述

这里面,只有forward_list、unordered_map、unordered_set的迭代器没有–的函数接口,剩下的都有。但是为什么呢?

因为迭代器也是分类的。
共三类:

  1. forward_iterator(单向迭代器)

只支持++

相关容器有:forward_list、unordered_map、unordered_set

  1. bidirectional_iterator(双向迭代器)

支持++和–

相关容器有:list、map、set

  1. random_access_iterator(随机访问迭代器)

支持++、–还有+和-

相关容器有:vector、deque

上面的相关容器我只给了常用的,一些不常用的没写上去。

这里三个迭代器是有继承关系的,但由于我前面还没有写过关于继承的博客,所以我只能略提一嘴。

但是文档中有一个表概括的非常全面,不过是英文的,这里截出来给大家看一眼:
在这里插入图片描述
不知道各位英文怎么样,如果实在看不懂,我把这个页面的网址给大家:<iterator>。 往下翻一翻就能看到。

上面的表中对应的有不同类型迭代器能够重载的操作符。
比如说+,Random Access可以重载,但是bidirectional和forward就不能。

根据这个关系就可以得出:双向可实现单向,随机也可实现双向和单向。

再来看个东西,库中的sort和reverse。

库中reverse和sort模板参数中的迭代器

reverse

在这里插入图片描述

sort

在这里插入图片描述

上面两个模板参数中其实已经在提示你改用什么样的迭代器了。
sort传容器的迭代器至少是随机访问迭代器,reverse传容器的迭代器至少是双向迭代器。

所以我们链表就不能用算法库中的sort,要自己实现一个,因为链表的迭代器是双向迭代器。

好了,该讲的都讲得差不多了。

到此结束。。。

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

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

相关文章

Ubuntu学习笔记(二)——文件属性与权限

文章目录 前言一、用户与用户组1.用户&#xff08;文件拥有者&#xff09;2.用户组3.其他人 二、Linux用户身份与用户组记录文件1. /etc/passwd2. /etc/shadow3. /etc/group 三、文件属性与权限1. 查看文件属性的方法&#xff08;ls&#xff09;2.文件属性详细介绍2.1 权限2.2 …

Python多个if代码优化

一、背景 大量的if … elif…代码非常难看&#xff0c;也很难维护。扩展不太方便 二、优化方案 以下栗子展示不同的角色获取折扣信息。 1、正常写法 def discount_algorithm(user_role):if user_role admin:discount 0.1return discountelif user_role msp:discount 0.…

【protobuf】socket.io序列化和反序列化

1.背景 后台利用socket.io发送websocket消息&#xff0c;加密用到protobuf 2.反序列化时遇到问题 Traceback (most recent call last): File "D:/locust/Nigeria/test3.py", line 40, in <module> play.ParseFromString(decode_spin_str) google.proto…

Cesium 实战 - 通过 Blender 将模型组件拆解为独立子模型

Cesium 实战 - 通过 Blender 将模型组件拆解为独立子模型 拆分模型1.导入模型&#xff08;J15.glb&#xff09;2.拆分模型3.保存模型 完整代码在线示例 上篇博客介绍了 Cesium 实战 - AGI_articulations 扩展&#xff1a;模型自定义关节动作 这篇接着介绍一下&#xff0c;模型…

【Redis】高可用之三:集群(cluster)

本文是Redis系列第6篇&#xff0c;前5篇欢迎移步 【Redis】不卡壳的 Redis 学习之路&#xff1a;从十大数据类型开始入手_AQin1012的博客-CSDN博客关于Redis的数据类型&#xff0c;各个文章总有些小不同&#xff0c;我们这里讨论的是Redis 7.0&#xff0c;为确保准确&#xf…

YZ04:文本批量替换使用说明文档

【分享成果&#xff0c;随喜正能量】达摩祖师说&#xff1a;“不谋其前&#xff0c;不虑其后&#xff0c;不恋当今。”你內心安适&#xff0c;就会宠辱不惊&#xff0c;俯仰无愧&#xff0c;从一天到一年&#xff0c;从一年到一生&#xff0c;秒秒感受安详&#xff0c;活在至真…

MySQL-数据库读写分离(中)

♥️作者&#xff1a;小刘在C站 ♥️个人主页&#xff1a; 小刘主页 ♥️努力不一定有回报&#xff0c;但一定会有收获加油&#xff01;一起努力&#xff0c;共赴美好人生&#xff01; ♥️学习两年总结出的运维经验&#xff0c;以及思科模拟器全套网络实验教程。专栏&#xf…

常见java知识点1

目录 1 什么是Spring框架&#xff1f;Spring框架有哪些主要模块&#xff1f; 2 使用Spring框架有什么好处&#xff1f; 3 Java常用的包&#xff08;列举六个&#xff09; 4 Arraylist 和 Linkedlist 的区别 5 HashMap和Hashtable的区别 6 Java中常见的…

vue-sticky简单使用(实现吸顶效果)

参考链接 vue-sticky&#xff1a;在页面滚动时将指定元素固定在窗口上的某个位置 生效条件如下&#xff1a; 1、父元素不能设置 overflow:hidden 或者 overflow:auto 属性 2、至少指定 top 、bottom 、left 、right 4 个值中的一个&#xff0c;否则只会处于相对定位 3、父元素…

OpenCVForUnity(六)图像的对比度和亮度

文章目录 前言公式讲解Unity嵌套循环实现使用convertTo实现亮度和对比度调整:伽马矫正 前言 图片处理中这也是非常常用的功能,下面我们一起来学习一下如何在OpenCVForUnity中修改图像的对比度亮度 图像处理中的常见算子可以将一个或多个输入图像转换为输出图像。这些变换包括点…

tdengine超级表创建

tdengine有官网文档&#xff0c;这里就把实际使用的SQL贴出来吧。 创建超级表&#xff1a; CREATE STABLE superTable(time TIMESTAMP, val double) TAGS (point varchar(100));执行SQL后会创建一个叫superTable的超级表。 建完超级表后再创建子表&#xff0c;SQL如下&#…

8、PHP访问权限配置与报错处理:You don‘t have permission to access this resource.

这是由于阿帕奇服务器的权限设置导致的。 解决办法&#xff1a; 1、由于我们之前已经设置了虚拟主机&#xff0c;我们在WAMPserver中&#xff0c;找到添加虚拟主机的配置文件的路径 2、打开这个文件&#xff0c;修改相应的虚拟主机的访问权限&#xff0c;Require后面改为all …

Cesium Terrain Builder (CTB) 简单使用_地形切片

Cesium Terrain Builder (CTB) 简单使用_地形切片 目录 Cesium Terrain Builder (CTB) 简单使用_地形切片 官网地址&#xff1a; winr&#xff08;cmd&#xff09;打开命令提示符工具运行&#xff1a; Create a GDAL Virtual Dataset (optional) Create Cesium Terrain fi…

CentOS系统下Docker安装部署Strapi

Nodejs 16 安装 移除旧版本的 node yum remove -y nodejs npm使用以下命令将存储库添加到系统 curl -fsSL https://rpm.nodesource.com/setup_16.x | sudo bash -配置存储库之后可以安装 yum install -y nodejs查看版本 node -v下载 yarn 包管理 curl -sL https://dl.yar…

数字化时代,智能文件工具让办公升级

无论是在办公室还是在学校&#xff0c;文件管理是我们日常工作中不可或缺的一环。传统的文件整理方式可能需要花费大量的时间和精力&#xff0c;而且常常容易出现混乱和遗漏。然而&#xff0c;随着科技的不断进步&#xff0c;我们现在有幸生活在一个数字化时代&#xff0c;因此…

ELK(elasticsearch+logstash+kibana+beats)

什么是ELK Elasticsearch&#xff1a;Elasticsearch&#xff08;以下简称ES&#xff09; 是一个分布式、RESTful 风格的搜索和数据分析引擎&#xff0c;能够解决不断涌现出的各种用例。 ES是 Elastic Stack 的核心&#xff0c;采用集中式数据存储&#xff0c;可以通过机器学习来…

ylb-接口2首页产品数据和接口3产品列表

总览&#xff1a; 1、service处理&#xff08;分页查询&#xff09; 在api模块下service包&#xff0c;创建一个产品接口ProductService&#xff1a;&#xff08;目前方法为分页查询queryByTypeLimit(Integer pType,Integer pageNo,Integer pageSize)&#xff09; package…

如何破解中小企业数字化转型难点?建议来了!

打开任何一个搜索引擎&#xff0c;只要输入“中小企业数字化转型”&#xff0c;关于痛点、难处的文章就会铺面而来&#xff0c;难在哪里&#xff0c;其实很好解答&#xff0c;关键在于&#xff0c;如何解决这一个个难处。 PS&#xff1a;给大家整理了一份完整版的《中小企业如…

物理层 ———— 奈氏准则 香农定理

1. 失真的现象----码间串扰 2.奈氏准则 eg: 3.香农定理 eg: 3.两个准则的比较

excel表格设置下拉选项

excel表格设置下拉选项 最后保存&#xff0c;即可设置完成。