C++中的reverse_iterator迭代器结构设计

news2024/11/19 11:21:41

目录

reverse_iterator迭代器结构设计

reverse_iterator迭代器基本结构设计

operator*()函数

operator++()函数

operator->()函数

operator!=()函数

rbegin()函数

rend()函数

operator--()函数

operator==()函数

测试代码

const_reverse_iterator迭代器设计

reverse_iterator迭代器结构设计思路改进


reverse_iterator迭代器结构设计

前面的list类以及vector类设计了正向迭代器,现在考虑设计反向迭代器,常规的设计思路为单独为反向迭代器建一个新类,这个类中所有的函数全部重新设计,这种思路可取但是并不高效,可以考虑下面的设计思路:

前面了解到了容器适配器,那么是否也可以把正向迭代器设置为反向迭代器的容器适配器从而实现反向迭代器的效果

对于此时的反向迭代器类设计即为如下:

以list类为例

reverse_iterator迭代器基本结构设计

//反向迭代器
 template<classIterator>
 class_list_reverse_iterator
 {
     typedef_list_reverse_iterator self;
     //使用正向迭代器构造反向迭代器
     _list_reverse_iterator(Iterator it)
         :_it(it)
     {}
 ​
 private:
     Iterator_it;
 };

operator*()函数

首先是对于operator*()函数来说,解引用操作符获得的结果即为指针当前指向中的内容,而在正向迭代器中,解引用操作符也是同样的作用,所以此处可以复用正向迭代器的解引用操作符,但是此处是Iterator类对象,所以不能使用传统的直接对内置类型解引用的方式,但是可以考虑直接调用Iterator类中的operator*()函数

对于返回值来说,可以考虑和设计const版本的正向迭代器思路一致,使用模板参数区分传递T&T*

所以修改原来的类定义为:

//反向迭代器
 template<class Iterator, class Ref, class Ptr>
 class _list_reverse_iterator
 {
     typedef _list_reverse_iterator self;
     //使用正向迭代器构造反向迭代器
     _list_reverse_iterator(Iterator it)
         :_it(it)
     {}
 ​
 private:
     Iterator _it;
 };

此时的operator*()函数即为如下设计:

//operator*()函数
 Ref operator*()
 {
     return _it.operator*();
 }

operator++()函数

对于前置++运算符来说,不同于正向迭代器,因为正向迭代器++是从第一个有效数据节点开始一直到头节点结束,而对于反向迭代器来说,其++是从最后一个有效数据节点开始向前一直到头节点结束,如下图所示:

但是可以考虑通过正向迭代器适配出反向迭代器,具体思路如下:

begin()放置在最后一个有效数据节点的位置,即end()-1的位置,将end()放在头节点的位置即可

所以,operator++()函数可以设计为

//operator++()函数
self& operator++()
{
    --_it;
    return *this;
}

operator->()函数

operator*()函数一样,调用Iterator中的operator->()函数即可

//operator->()函数
 Ptr operator->()
 {
     return _it.operator->();
 }

operator!=()函数

同正向迭代器中的设计思路一致

//operator!=()函数
bool operator!=(self& s)
{
    return _it != s._it;
}

rbegin()函数

//rbegin()函数——反向——非const版本
reverse_iterator rbegin()
{
    //因为正向迭代器中没有重载-,所以使用--代替
    return reverse_iterator(--end());
}

rend()函数

//rend()函数——反向——非const版本
reverse_iterator rend()
{
    return reverse_iterator(end());
}

operator--()函数

//operator--()函数
self& operator--()
{
    ++_it;
    return *this;
}

operator==()函数

//operator==()函数
bool operator==(const self& s)
{
    return _it == s._it;
}

测试代码

此时基本的反向迭代器框架已经搭建完成,下面是测试代码:

void test_reverse_iterator()
{
    sim_list::list<int> ls;
    ls.push_back(1);
    ls.push_back(2);
    ls.push_back(3);
    ls.push_back(4);
    ls.push_back(5);

    sim_list::list<int>::reverse_iterator rit = ls.rbegin();
    while (rit != ls.rend())
    {
        cout << *rit << " ";
        ++rit;
    }
}

const_reverse_iterator迭代器设计

对于const_reverse_iterator设计来说,不需要更改reverse_iterator迭代器的结构,只需要在list类中重定义一个const版本即可

typedef _list_reverse_iterator<iterator, T&, T*> reverse_iterator;// 反向迭代器——非const版本
typedef _list_reverse_iterator<iterator, const T&, const T*> const_reverse_iterator // 反向迭代器——const版本

并且将rbegin()rend()分别重载一个const版本

//rbegin()函数——反向——const版本
reverse_iterator rbegin() const
{
    //因为正向迭代器中没有重载-,所以使用--代替
    //注意end()此处是常量,但是此处是调用了operator--(),所以可以调用(编译器对const类型能调用普通函数的优化),如果是内置指针类型则必须写成end()-1
    return reverse_iterator(--end());
}

//rend()函数——反向——const版本
reverse_iterator rend() const
{
    return reverse_iterator(end());
}

reverse_iterator迭代器结构设计思路改进

前面在设计reverse_iterator迭代器时,直接考虑的rbegin()函数的位置在最后一个有效节点的位置,而rend()在则在end()的位置,这样的思路并没有错误,但是参照SGI版本中的设计:

rbegin()rend()设计

可以看出,SGI版本在设计rbegin()rend()时考虑到和begin()end()形成了一种对称关系,如下图所示:

那么此时SGI版本中的反向迭代器是如何处理operator*()函数的

配合rbegin()rend()遍历思路如下:

取出上一个有效节点的数据,因为rbegin()在头节点的位置,所以先取出最后一个节点的数据,迭代器--操作到最后一个有效节点,一直到rend()位置结束

参考完SGI版本的迭代器设计,此时可以对上面的设计进行优化为SGI版本

//operator*()函数
Ref operator*()
{
    Iterator cur = _it;
    //如果不实现--,也可以用-1来代替
    return *(--cur);
}

//rbegin()函数——反向——非const版本
reverse_iterator rbegin()
{
    //因为正向迭代器中没有重载-,所以使用--代替
    return reverse_iterator(end());
}

//rend()函数——反向——非const版本
reverse_iterator rend()
{
    return reverse_iterator(begin());
}

//rbegin()函数——反向——const版本
reverse_iterator rbegin() const
{
    //因为正向迭代器中没有重载-,所以使用--代替
    return reverse_iterator(end());
}

//rend()函数——反向——const版本
reverse_iterator rend() const
{
    return reverse_iterator(begin());
}

此时对于operator->()函数来说,则需要换一个实现思路:直接取当前operator*()结果的地址

//operator->()函数
Ptr operator->()
{
    return &(operator*());
}

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

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

相关文章

【数据结构】第四讲:双向链表

目录 一、链表的分类 二、双向链表的结构及实现 1.带头双向链表的结构 2.创建节点 3.初始化 4.尾插 5.打印 6.头插 7.尾删 8.头删 9.在pos位置之后插入数据 10.删除pos节点 11.查找 12.销毁 个人主页&#xff1a;深情秋刀鱼-CSDN博客 数据结构专栏&#xff1a;数…

java基于云计算的SaaS医院his信息系统源码 HIS云平台源码

目录 云HIS功能模块 1、预约挂号&#xff1a; 2、药库管理&#xff1a; 3、门诊医生站&#xff1a; 4、门诊费用&#xff1a; 5、药房管理&#xff1a; 6、治疗室&#xff08;门诊护士工作站&#xff09;&#xff1a; 7、统计分析&#xff1a; 8、财务管理&#xff1a;…

vue 时间轴页面 自己的写法 欢迎交流指正

<div class"first-box"><!--贯穿线--><div class"vertical-line-wrap"><div class"vertical-line"></div><div class"vertical-line-arrow"></div></div><!--开始--><div c…

数据存储-SD卡存储

手机自带内存较小&#xff0c;不适合存储大量数据&#xff0c;一般&#xff0c;大量数据都会采用外部存储&#xff0c;如&#xff1a;服务器存储、SD卡存储、数据库存储等。 本文讲解在SD卡上存储数据&#xff0c;并实现对数据的读和写。 整体思路&#xff1a;静态权限声明、动…

第五篇:通信脉络:探索计算机外设与总线体系的精髓

通信脉络&#xff1a;探索计算机外设与总线体系的精髓 1 引言 在这个技术日新月异的时代&#xff0c;理解计算机系统的基本构成要素 —— 总线和外设 —— 对于每个从事技术工作的人来说都是至关重要的。这些组件不仅是计算机通信的基石&#xff0c;也直接影响着系统的性能、效…

非对称齿轮的跨棒距算的对不对

前面有一期咱们聊了非对称齿轮《》&#xff0c;非对称齿轮的齿厚测量一般都为跨棒距。最近研究了下计算方法&#xff0c;对计算结果的正确性做了下验证。 在MATLAB中编制了相关的计算程序&#xff1a; 齿轮的模数4&#xff0c;左侧分度圆压力角25&#xff0c;右侧分度圆压力角…

CARIS12如何设置kmall船型文件?

最近我们对船上多波束EM2040D的采集软件进行了升级&#xff0c;从SIS4.3升级至SIS5。当使用CARIS11/12处理kmall数据时&#xff0c;发现往返横切海底线性目标时有10-20m错位。 ​编辑​ 我们开始怀疑SIS5采集的设置有问题&#xff0c;似乎跟时间延迟有关系。但是改了如下图两…

JAVA系列 小白入门参考资料 接口

目录 接口 接口的概念 语法 接口使用 接口实现用例 接口特性 实现多个接口和实现用例 接口间的继承 接口 接口的概念 在现实生活中&#xff0c;接口的例子比比皆是&#xff0c;比如&#xff1a;笔记本上的 USB 口&#xff0c;电源插座等。 电脑的 USB 口上&am…

初学python记录:力扣1235. 规划兼职工作

题目&#xff1a; 你打算利用空闲时间来做兼职工作赚些零花钱。 这里有 n 份兼职工作&#xff0c;每份工作预计从 startTime[i] 开始到 endTime[i] 结束&#xff0c;报酬为 profit[i]。 给你一份兼职工作表&#xff0c;包含开始时间 startTime&#xff0c;结束时间 endTime …

水仙花数问题

问题描述&#xff1a; 求出0&#xff5e;100000之间的所有“水仙花数”并输出。 “水仙花数”是指一个n位数&#xff0c;其各位数字的n次方之和确好等于该数本身&#xff0c;如:153&#xff1d;1^3&#xff0b;5^3&#xff0b;3^3&#xff0c;则153是一个“水仙花数”。 #in…

对链表进行插入排序(详细解析)

对链表进行插入排序&#xff08;详解&#xff09; 题目&#xff1a; 对链表进行插入排序 给定单个链表的头 head &#xff0c;使用 插入排序 对链表进行排序&#xff0c;并返回 排序后链表的头 。 插入排序 算法的步骤: 插入排序是迭代的&#xff0c;每次只移动一个元素&a…

CUDA和显卡驱动

1.安装显卡驱动 https://www.nvidia.com/download/index.aspx?langen-us 由于我的显卡是RTX4060&#xff0c;因此先选择RTX40系列&#xff0c;然后选择RTX4060&#xff0c;进行安装 2.查看显卡对应的CUDA CUDA安装地址&#xff1a;https://developer.nvidia.com/cuda-toolk…

数据库(MySQL)—— 事务

数据库&#xff08;MySQL&#xff09;—— 事务 什么是事务事务操作未控制事务测试异常情况 控制事务一查看/设置事务提交方式&#xff1a;提交事务回滚事务 控制事务二开启事务提交事务回滚事务 并发事务问题脏读&#xff08;Dirty Read&#xff09;不可重复读&#xff08;Non…

小红书流量机制解析

小红书流量机制解析 前言 大家好&#xff0c;我自2020年5月起&#xff0c;开始专注于小红书平台&#xff0c;帮助品牌商家在小红书上经营。在这段时间里&#xff0c;我深入研究了小红书的流量机制&#xff0c;并结合自己的实践经验&#xff0c;为大家带来了这份全网最硬核的小…

【面试经典 150 | 字典树】实现 Trie (前缀树)

文章目录 写在前面Tag题目来源解题思路方法一&#xff1a;前缀树 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等内容进行回…

复旦微JFM7VX690计算后IO接口模块,用于雷达信号处理、数据处理等需要高速密集计算的应用场景

计算后IO接口模块 1 介绍 1.1 产品概述 计算后IO接口模块主要由复旦微JFM7VX690型FPGA、国产以太网收发器YT8521、国产BMC芯片GD32F450、国产CPLD芯片EF2L45BG256B、国产内存颗粒等主要芯片组成&#xff0c;采用标准6U VPX尺寸设计。 本计算后IO接口模块主要用于雷达信号处…

实习与就业|基于Springboot+vue的实习与就业管理系统(源码+数据库+文档)

实习与就业目录 基于Springbootvue的实习与就业管理系统 一、前言 二、系统设计 三、系统功能设计 管理员登录 就业管理 企业公告信息管理 企业公告类型管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主…

SDB2F5 首鼎1.2MHz 输入5V 输出28V 100mA升压DC-DC转换器

SDB2F5是一款固定频率&#xff0c;内部的软启动有很小脉冲电流可延长电池寿命。SDB2F5最低输入电压为2.5V&#xff0c;在输入电压为5V的时候可升压到28V 100mA。SDB2F5在轻负载时自动转成脉冲频率调制模式。SDB2F5有欠压锁定&#xff0c;限流和热过载保护。 特点&#xff1a; …

链舞算法谱---链表经典题剖析

前言&#xff1a;探究链表算法的奥秘&#xff0c;解锁编程新世界&#xff01; 欢迎来到我的链表算法博客&#xff0c;这将是您深入了解链表算法&#xff0c;提升编程技能的绝佳机会。链表作为数据结构的重要成员之一&#xff0c;其动态性和灵活性在实现某些功能上发挥不可替代的…

深入理解 Java 并发:AbstractQueuedSynchronizer 源码分析

序言 在多线程编程中&#xff0c;同步机制是保障线程安全和协调线程之间操作顺序的重要手段。AQS 作为 Java 中同步机制的基础框架&#xff0c;为开发者提供了一个灵活且高效的同步工具。本文将通过对 AQS 源码的分析&#xff0c;解读 AQS 的核心实现原理&#xff0c;并深入探…