【c++】反向迭代器的探究实现

Alt

🔥个人主页Quitecoder

🔥专栏c++笔记仓

Alt

在list中我们实现了正向的迭代器,学习完优先级队列后,我们也对适配器模式有了一个深刻的理解,这篇文章基于这种模式下,实现各类容器的反向迭代器

目录

  • 1.引入:list的反向迭代器
  • 2.适配实现反向迭代器
      • 1. 构造函数:
      • 2. 解引用操作符 `operator*`:
      • 3. 成员访问操作符 `operator->`:
      • 4. 前置自增操作符 `operator++`:
      • 5. 前置自减操作符 `operator--`:
      • 6. 不等于操作符 `operator!=`:
      • 总结编译器处理:

1.引入:list的反向迭代器

首先来回顾一下我们实现list的正向迭代器:

	template<class T, class Ref, class Ptr>struct ListIterator{typedef ListNode<T> Node;typedef ListIterator<T, Ref, Ptr> Self;Node* _node;ListIterator(Node* node):_node(node){}// *it//T& operator*()Ref operator*(){return _node->_data;}// it->//T* operator->()Ptr operator->(){return &_node->_data;}// ++itSelf& operator++(){_node = _node->_next;return *this;}Self operator++(int){Self tmp(*this);_node = _node->_next;return tmp;}Self& operator--(){_node = _node->_prev;return *this;}Self operator--(int){Self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const Self& it){return _node != it._node;}bool operator==(const Self& it){return _node == it._node;}};

在list类里面这样声明:

template<class T>
class list {// ... 省略其他代码 ...
public:typedef ListIterator<T, T&, T*> iterator;typedef ListIterator<T, const T&, const T*> const_iterator;// ... 省略其他代码 ...
};

为了实现一个反向迭代器,需要创建一个新的迭代器类,该类的增加(operator++)和减少(operator--操作符与标准迭代器的行为相反。也就是说,对于一个反向迭代器,operator++将会移动到前一个元素(_prev),而operator--将会移动到下一个元素(_next)。这意味着它将沿着相反的方向遍历列表。以下是如何定义一个ListIterator的反向版本的示例:

template<class T, class Ref, class Ptr>
struct ReverseListIterator
{typedef ListNode<T> Node;typedef ReverseListIterator<T, Ref, Ptr> Self;Node* _node;ReverseListIterator(Node* node):_node(node){}// 解引用操作符Ref operator*(){return _node->_data;}// 成员访问操作符Ptr operator->(){return &_node->_data;}// 前置自增操作符,移动到前一个元素Self& operator++(){_node = _node->_prev;return *this;}// 后置自增操作符,移动到前一个元素Self operator++(int){Self tmp(*this);_node = _node->_prev;return tmp;}// 前置自减操作符,移动到下一个元素Self& operator--(){_node = _node->_next;return *this;}// 后置自减操作符,移动到下一个元素Self operator--(int){Self tmp(*this);_node = _node->_next;return tmp;}bool operator!=(const Self& it){return _node != it._node;}bool operator==(const Self& it){return _node == it._node;}
};

这里的ReverseListIterator和原来的ListIterator很相似,区别就在于迭代器前进(++)和后退(--)的方向相反

通常情况下,标准库容器(比如listvector)会有.rbegin().rend()方法来获取反向迭代器的开始和结束。为了实现类似的功能,需要在容器类中添加生成ReverseListIterator实例的方法:

typedef ReverseListIterator<T, T&, T*> reverse_iterator;
typedef ReverseListIterator<T, const T&, constT*>const_reverse_iterator;reverse_iterator rbegin()
{return reverse_iterator(end());
}reverse_iterator rend()
{return reverse_iterator(begin());
}

2.适配实现反向迭代器

typedef ReverseListIterator<T, T&, T*> reverse_iterator;
typedef ReverseListIterator<T, const T&, constT*>const_reverse_iterator;reverse_iterator rbegin()
{return reverse_iterator(end());
}reverse_iterator rend()
{return reverse_iterator(begin());
}

这种实现只是对原有类的一个修改,只是对list这个反向迭代器的实现,我们下面来实现另一种适配模式,我传入某一容器的正向迭代器来适配生成反向迭代器

比如传入List类的正向迭代器,适配出List的反向迭代器,传入vector正向迭代器,适配出vector的反向迭代器

template<class Iterator, class Ref, class Ptr>struct ReverseIterator{typedef ReverseIterator<Iterator, Ref, Ptr> Self;Iterator _it;ReverseIterator(Iterator it):_it(it){}Ref operator*(){Iterator tmp = _it;return *(--tmp);}Ptr operator->(){//return _it->;//return _it.operator->();return &(operator*());}Self& operator++(){--_it;return *this;}Self& operator--(){++_it;return *this;}bool operator!=(const Self& s){return _it != s._it;}};
}

在这个模板代码示例中,ReverseIterator 类型是一个反向迭代器,它是基于提供的正向迭代器类型 Iterator 来实现的当使用 ReverseIterator 时,编译器将会按照模板代码的描述来生成一个特定于所使用迭代器类型的类实例。以下是各个操作符和成员函数的作用,以及编译器如何处理它们:

1. 构造函数:

ReverseIterator(Iterator it) : _it(it) {}

构造函数接收一个正向迭代器 it 并存储在 _it 成员变量中。编译器处理构造函数的方式与普通的构造函数相同

2. 解引用操作符 operator*

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

这个操作符创建了 _it 的一个副本 tmp,然后对 tmp 应用前置自减 operator--,将其后移一位,然后解引用。对于反向迭代器而言,这意味着解引用的是当前位置之前的元素。

编译器生成了一个临时变量 tmp,调用了对应类型 Iterator 的前置自减 operator--,并调用了解引用 operator*。注意,由于这是一个底层实现细节,编译器有权优化这些步骤(如通过直接调用必要的函数)以优化性能

3. 成员访问操作符 operator->

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

这个操作符通过调用解引用操作符 operator* 来获取值的引用,然后取地址得到对应元素的指针

编译器会生成代码,使用上面定义的解引用操作符 operator* 来获取一个引用,然后获取该引用的地址

4. 前置自增操作符 operator++

Self& operator++()
{--_it;return *this;
}

对于反向迭代器来说,“自增”实际上会使内部正向迭代器 _it 自减。编译器调用 _it 的前置自减操作符 operator-- 并返回 *this 实现反向迭代器的自增操作

5. 前置自减操作符 operator--

Self& operator--()
{++_it;return *this;
}

对于反向迭代器来说,“自减”实际上会使内部正向迭代器 _it 自增。编译器调用 _it 的前置自增操作符 operator++ 并返回 *this 实现反向迭代器的自减操作

6. 不等于操作符 operator!=

bool operator!=(const Self& s)
{return _it != s._it;
}

这个操作符比较两个反向迭代器,实际上它比较了内部正向迭代器 _it 是否不相等。

编译器根据 Iterator 类型生成了比较操作,这通常是调用 Iterator 给定的 operator!=

总结编译器处理:

本来每个容器都要写一个反向迭代器的累,但是自己写,太费劲了 本质写一个反向迭代器的类模板,给编译器传不同的容器的正向迭代器实例化,编译器帮助我们实例化出各种容器的对应反向迭代器

编写一个通用的反向迭代器类模板可以省去为每个容器单独定义反向迭代器的麻烦。C++ 标准库中的 std::reverse_iterator 就是这样一个通用的反向迭代器适配器。它接收一个正向迭代器作为模板参数,反转了其遍历方向,使得利用正向迭代器的容器可以很容易地提供反向迭代能力

使用类模板可以使得编译器根据你向模板传递的不同正向迭代器类型,为每个具体的容器类型生成对应的反向迭代器实例。这个通用反向迭代器适配器遵循了一种 编写一次,处处使用的原则,极大地提高了代码的复用性

例如,在 ReverseIterator 模板中,只要定义一次,就可以用来产生各种支持正向迭代器的容器的反向迭代器,如下所示:

std::vector<int> vec = {1, 2, 3, 4, 5};
ReverseIterator<std::vector<int>::iterator, int&, int*> rIt(vec.end());// 使用反向迭代器遍历 vector
for (; rIt != ReverseIterator<std::vector<int>::iterator, int&, int*>(vec.begin()); ++rIt) {std::cout << *rIt << " ";
}

在这段代码中,ReverseIteratorstd::vector<int>::iterator 类型进行了实例化。实际上,因为 std::reverse_iterator 已经存在于标准库中,通常不需要自己写这个,并且可以直接这样使用

std::vector<int>::reverse_iterator rIt = vec.rbegin();
// 标准库已经提供 begin 和 end 了,不需要我们手动构建 ReverseIterator 实例
for (; rIt != vec.rend(); ++rIt) {std::cout << *rIt << " ";
}

本篇文章到此结束!!感谢大家阅读!!

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

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

相关文章

Docker-compose部署LTC同步节点

1、下载ltc程序包&#xff0c;litecoin下载地址 下载页 mkdir /data/docker-compose/ltc cd /data/docker-compose/ltc https://github.com/litecoin-project/litecoin/releases/download/v0.21.3/litecoin-0.21.3-x86_64-linux-gnu.tar.gz2、编写dockerfile和bitcoin.conf b…

我开始接单/兼职/搞副业/建设个人社区,为自己谋后路了。

我开始接单/兼职/搞副业/建设个人社区&#xff0c;为自己谋后路了。 简述 大家好&#xff0c;我是小荣&#xff0c;一个前端开发程序员。我最近开始在业余时间接私单了&#xff0c;也在想一些能够带来成长&#xff0c;收入的副业&#xff0c;主要也是为了自己谋后路&#xff…

C语言:数据结构(双向链表)

目录 1、双向链表的结构2、顺序表和双向链表的优缺点分析3、双向链表的实现 1、双向链表的结构 注意&#xff1a;这⾥的“带头“跟前面我们说的“头节点”是两个概念&#xff0c;实际前面的在单链表阶段称呼不严谨&#xff0c;但是为了更好的理解就直接称为单链表的头节点。 带…

SSH远程登录实操实验!

ssh远程登录协议&#xff1a;默认端口号22 以下实验7-2是服务端&#xff0c;7-1是客户端 服务器的相关信息&#xff1a; 服务名称&#xff1a;sshd 服务端主程序&#xff1a;/usr/sbin/sshd 服务端配置文件&#xff1a;/etc/ssh/sshd_config 客户端相关信息&#xff1a; …

python的输入输出(爽文,备忘,查询,友好)

Python中的输入输出主要涉及到输入函数和输出函数。 输出函数&#xff1a;print() print() 函数用于将信息输出到屏幕上。它可以输出字符串、变量的值&#xff0c;以及其他各种数据类型。 name "Alice" age 30 print("姓名:", name, "年龄:&quo…

ip ssl证书无限端口网站

IP SSL证书是由CA认证机构颁发的一种特殊数字证书。大部分SSL数字证书都需要用户使用域名进行申请&#xff0c;想要对公网IP地址加密实现https访问就需要申请IP SSL证书。IP SSL证书采用了强大的加密算法&#xff0c;可以有效地防止数据在传输过程中被窃取或篡改&#xff0c;具…

[C语言]典型例题:小蚂蚁爬橡皮筋、买汽水问题、导致单词块、菱形打印……

1、小蚂蚁爬橡皮筋问题 假设橡皮筋长4m&#xff0c;小蚂蚁从一端爬向另一端每天爬1m&#xff0c;且每爬了1m&#xff0c;橡皮筋会立马拉伸4m&#xff0c;在理想条件下&#xff0c;小蚂蚁需要爬多少天可以到达橡皮筋的另一端&#xff1f; 不仔细想&#xff0c;我们很可能认为小蚂…

Scikit-Learn回归树

Scikit-Learn回归树 1、决策树1.1、什么是决策树1.2、决策树学习的步骤1.3、决策树算法 1、决策树 决策树&#xff08;DTs&#xff09;是一种用于回归和分类的有监督学习方法。通常&#xff0c;决策树用于分类问题&#xff1b;当决策树用于回归问题时&#xff0c;称为回归树。回…

【C++】:日期类的实现 -- 日期计算器

前言 1.日期类是一种十分经典的类型。对于C的初学者&#xff0c;它能够帮助我们融会贯通许多C的基础知识&#xff0c;它涉及许多的基础语法&#xff0c;比如引用&#xff0c;函数重载&#xff0c;传值/传参返回&#xff0c;构造函数&#xff0c;运算符重载&#xff0c;const成…

【Python小练】求斐波那契数列第n个数

题目 输出斐波那契数列第n个数。 分析 首先我们要知道&#xff0c;斐波那契数列&#xff0c;这个数列从第三位开始等于前两个数的和&#xff0c;要知道数列第n个数&#xff08;n>2&#xff09;&#xff0c;就要知道其前两相的值&#xff0c;着就需要用到递归了。来看一下吧…

C语言实验-循环结构和选择结构

一&#xff1a; 求和:1(14)(149)(14916)…(14916…n2)? 其中n的值由键盘输入&#xff1b; #define _CRT_SECURE_NO_WARNINGS #include<stdio.h>int main() {int sum 0;int n 0;printf("请输入一个整数");scanf("%d", &n);for (int i 0; i &l…

Apache中如何配置 ws 接口

Apache中如何配置 wss 接口 在Apache中配置WebSockets的支持&#xff0c;你需要使用mod_proxy_wstunnel模块&#xff0c;该模块是Apache的一个代理模块&#xff0c;它允许你代理WebSocket请求。 以下是配置步骤的简要说明和示例&#xff1a; 确保你的Apache服务器安装了mod_…

【最大公约数 排序】2344. 使数组可以被整除的最少删除次数

本文涉及知识点 最大公约数 排序 LeetCode2344. 使数组可以被整除的最少删除次数 给你两个正整数数组 nums 和 numsDivide 。你可以从 nums 中删除任意数目的元素。 请你返回使 nums 中 最小 元素可以整除 numsDivide 中所有元素的 最少 删除次数。如果无法得到这样的元素&a…

【高质量】2024五一数学建模C题保奖思路+代码(后续会更新)

你的点赞收藏是我后续更新的最大动力&#xff01; 一定要点击文末的卡片&#xff0c;那是获取资料的入口&#xff01; 你是否在寻找数学建模比赛的突破点&#xff1f; 作为经验丰富的数学建模团队&#xff0c;我们将为你带来2024 年五一数学建模&#xff08;C题&#xff09;…

1700java进销存管理系统Myeclipse开发sqlserver数据库web结构java编程计算机网页项目

一、源码特点 java web进销存管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为sqlser…

Vue通过下拉框选择字典值,并将对应的label以及value值提交到后端

产品品种从字典中获取 产品性质也是从字典中获取 字典当中的保存 dict_type表 dict_data表 在表单提交的方法中 1.因为做的产品性质是多选&#xff0c;它会以数组的方式提交&#xff0c;所以需要先将Json格式转变为String JSON.stringify(this.form.nature) 2.提交表单&…

【Linux网络编程】DNS、ICMP、NAT技术、代理服务器+网络通信各层协议总结

DNS、ICMP、NAT技术、代理服务器网络通信总结 1.DNS2.ICMP协议2.1ping命令2.2traceroute命令 3.NAT技术4.NAT和代理服务器5.网线通信各层协议总结 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&…

vue3 依赖-组件tablepage-vue3版本1.0.3更新内容

github求⭐ 可通过github 地址和npm 地址查看全部内容 vue3 依赖-组件tablepage-vue3说明文档&#xff0c;列表页快速开发&#xff0c;使用思路及范例-汇总 vue3 依赖-组件tablepage-vue3说明文档&#xff0c;列表页快速开发&#xff0c;使用思路及范例&#xff08;Ⅰ&#…

JAVAEE—servlet的概念及使用,使用servlet接口实现一个表白墙

文章目录 servlet的概念静态页面和动态页面servlet的作用 写出一个servlet程序目录的创建设置smart tomcat编写helloworld servlet的概念 首先我们要搞明白什么是servlet&#xff0c;servlet是一种实现动态页面的技术&#xff0c;他是由tomcat提供给程序员的一组API可以帮助程…

【学习笔记二十九】EWM较特殊的业务场景

一、供应商寄售业务相关 1.创建寄售物料、寄售信息记录以及寄售的采购订单 2.创建交货单 3.维护入库交货 行项目里存在C寄售的标识 4.创建上架的仓库任务并确定 查看仓位库存&#xff0c;发现仓位库存里存在寄售标识C以及寄售库存所有方 5.寄售转自有 ①首先MIGO里进行寄…