细说C++反向迭代器:原理与用法

文章目录

  • 一、引言
  • 二、反向迭代器的原理与实现细节
  • 三、模拟实现C++反向迭代器
      • 反向迭代器模板类的设计
      • 反向迭代器的使用示例与测试

一、引言

  1. 迭代器与反向迭代器的概念引入

迭代器(Iterator)是C++标准模板库(STL)中的一个核心概念,它提供了一种访问容器中元素的方式,而无需了解容器底层的实现细节。迭代器就像是一个指向容器中元素的指针,通过它可以遍历容器中的元素,进行读取、修改或删除操作。

反向迭代器(Reverse Iterator)则是迭代器的一个变种,它允许我们从后向前遍历容器中的元素。反向迭代器的出现极大地丰富了C++中容器的遍历方式,特别是在需要逆向操作容器元素时,提供了极大的便利。

  1. 反向迭代器在C++中的重要作用

反向迭代器在C++中扮演着至关重要的角色。在处理一些需要逆向遍历容器的场景时,如从后向前打印数组元素、逆序遍历链表节点等,使用反向迭代器可以大大简化代码逻辑,提高代码的可读性和可维护性。此外,反向迭代器还使得一些复杂的算法实现变得更加简单和直观。

本文将详细介绍C++中反向迭代器的概念、原理和使用方法,并通过模拟实现一个简单的反向迭代器来加深读者对反向迭代器的理解。通过本文的学习,读者将能够掌握反向迭代器的基本用法,并能够在实际编程中灵活运用反向迭代器来处理各种需要逆向遍历容器的场景。


二、反向迭代器的原理与实现细节

  1. 反向迭代器的内部机制

反向迭代器是一种特殊的迭代器,它的内部机制基于容器的正向迭代器。通常,反向迭代器在内部持有一个指向容器末尾之后位置的迭代器,或者一个指向容器第一个元素之前的迭代器,这取决于容器的具体实现。当对反向迭代器进行自增或自减操作时,它实际上是在对内部的正向迭代器进行相反的操作,从而实现从后向前的遍历。因此我们在模拟实现反向迭代器时,通常以原容器的正向迭代器为成员,所谓 reverse_iterator ,可以将迭代器的行进方向逆转,使原本应该前进的 operator++ 变成了后退操作, operator--变成了前进操作。

  1. 反向迭代器的设计与实现要点

设计并实现一个反向迭代器需要考虑以下几个要点:

  • 迭代器类型的选择:反向迭代器需要基于某种正向迭代器进行实现。因此,首先需要确定所针对的容器类型及其对应的正向迭代器类型。

  • 解引用与箭头操作符的重载:反向迭代器需要重载解引用操作符(*)和箭头操作符(->),以便能够正确地访问容器中的元素。这通常涉及对内部正向迭代器的相应操作,以确保访问的是正确的元素。

  • 反向遍历的实现:反向迭代器的核心功能是从后向前遍历容器。这通常通过调整正向迭代器的位置来实现。例如,在每次自增操作中,反向迭代器实际上会使内部的正向迭代器向前移动一个位置,从而模拟出从后向前的遍历效果。为了配合迭代器区间的“前闭后开”,我们通常按下图方式设计反向迭代器:

    在这里插入图片描述

  1. 反向迭代器与STL容器的结合使用

在C++标准模板库中,许多容器都提供了反向迭代器的支持。例如,vectorliststring等容器都提供了rbegin()rend()成员函数,用于获取指向容器末尾和末尾之后位置的反向迭代器。通过这些反向迭代器,我们可以方便地实现从后向前的遍历操作。

在实际使用中,我们可以将反向迭代器与范围基于的for循环(C++11及以后版本)或传统的while循环结合使用,来处理需要逆向遍历容器的场景。反向迭代器的使用方式与正向迭代器类似,只是遍历的方向相反而已。


三、模拟实现C++反向迭代器

在C++中,反向迭代器是一种特殊的迭代器,它允许我们按照相反的顺序遍历容器中的元素。在本节中,我们将模拟实现一个通用的反向迭代器模板类,并详细解释其设计、实现以及使用示例。

反向迭代器模板类的设计

为了设计一个通用的反向迭代器模板类,我们需要考虑以下几个关键部分:

  1. 模板参数的选择与意义

    ReverseIterator类的模板参数中,IteratorRefPtr的选择和它们各自的意义如下:

    • IteratorIterator是一个模板参数,它代表了正向迭代器的类型。这个类型通常是一个STL迭代器或者类似的自定义迭代器,用于遍历容器(如vectorlist等)。在ReverseIterator中,Iterator类型用于内部存储,并且在进行反向遍历的时候,它将被用来模拟反向迭代的行为。

    • Ref是另一个模板参数,用于指定operator*的返回类型。它应该是一个引用类型,这样operator*才能返回当前反向迭代器指向的元素的引用。返回引用允许用户直接修改通过反向迭代器访问的元素的值。

    在大多数情况下,Ref可以简单地设置为Iteratorvalue_type&,其中value_type是正向迭代器所指向元素的类型。例如,如果Iteratorvector<int>::iterator,那么Ref就应该是int&

    • Ptr是第三个模板参数,用于指定operator->的返回类型。它应该是一个指针类型,这样operator->才能返回当前反向迭代器指向的元素的指针。这个指针类型通常用于通过->操作符访问元素的成员。

    同样地,Ptr可以设置为Iteratorvalue_type*。对于上面的vector<int>::iterator示例,Ptr就是int*

    template<class Iterator, class Ref, class Ptr>
    class ReverseIterator {
    public:
        typedef ReverseIterator<Iterator, Ref, Ptr> Self;
    	//...
    }
    
  2. 成员变量与构造函数的实现

    • 成员变量_it:存储正向迭代器的实例,用于实现反向遍历。 Iterator _it; // 存储正向迭代器

    • 构造函数:接受一个正向迭代器作为参数,初始化成员变量_it ReverseIterator(Iterator it) : _it(it) {}

  3. 反向迭代器核心操作符的重载

    • 自增与自减操作符operator++operator--。反向迭代器的自增操作应模拟反向遍历,因此operator++应使内部的正向迭代器向前移动一位,而operator--则应使正向迭代器向后移动一位。
    Self& operator++() {
        --_it; // 使正向迭代器向前移动一位,模拟反向迭代器的自增
        return *this;
    }
    
    Self& operator--() {
        ++_it; // 使正向迭代器向后移动一位,模拟反向迭代器的自减
        return *this;
    }
    
    • 解引用与箭头操作符operator*operator->。这些操作符应返回当前反向迭代器指向的元素的引用或指针。
    Ref operator*() const {  
        Iterator cur = _it;  
        return *--cur; // 返回当前反向迭代器指向的元素的引用  
    }  
      
    Ptr operator->() const {  
        return &(this->operator*()); // 返回当前反向迭代器指向的元素的指针  
    }
    

    operator*成员函数用于获取反向迭代器当前指向的元素的引用。它首先创建一个_it的副本cur,以避免修改原始的_it。然后,它递减cur以模拟反向迭代器的行为(因为_it实际上是正向迭代器)。递减后,cur指向了当前反向迭代器所代表的元素,并返回这个元素的引用。

    operator->成员函数用于获取当前反向迭代器指向的元素的指针。它通过调用operator*来获取元素的引用,并取这个引用的地址来得到指针。这允许我们像使用普通指针一样,通过->操作符来访问对象的成员。

    例如,如果_it指向vector的末尾(end()),那么cur递减后就会指向最后一个元素。每次递增反向迭代器时,_it实际上是递减的,所以每次调用operator*时,我们都需要递减cur来获取正确的元素。operator->成员函数用于获取当前反向迭代器指向的元素的指针。它通过调用operator*来获取元素的引用,并取这个引用的地址来得到指针。这允许我们像使用普通指针一样,通过->操作符来访问对象的成员。

    需要注意的是,这种实现假设Iterator(即正向迭代器)支持operator*operator->,并且返回的类型与RefPtr兼容。在标准库中的迭代器类型中,这通常是成立的。但对于自定义迭代器类型,需要确保这些操作符的行为符合预期。

    • 比较操作符operator!=operator==。用于比较两个反向迭代器是否指向相同的位置。
    bool operator!=(const Self& s) const { return _it != s._it; }
    bool operator==(const Self& s) const { return _it == s._it; }
    

反向迭代器的使用示例与测试

为了测试我们实现的反向迭代器,我们可以使用一个简单的整数数组作为示例,并创建一个基于该数组的反向迭代器:

#include <iostream>
#include <iterator>
#include <vector>
 
using namespace std;
int main() {
    std::vector<int> vec = { 1, 2, 3, 4, 5 };
    ReverseIterator<vector<int>::iterator,int&,int*> rbegin(vec.end());
    ReverseIterator<vector<int>::iterator, int&, int*> rend(vec.begin());

    // 使用基于范围的for循环遍历反向迭代器
    for (ReverseIterator<vector<int>::iterator, int&, int*> it = rbegin; it != rend; ++it) {
        cout << *it << " "; // 输出:5 4 3 2 1 
    }
    cout << endl;
    ReverseIterator<vector<int>::iterator, int&, int*> it = rbegin;
    // 测试自增和自减操作符
    it++; // 现在it指向4
    cout << *it << endl; // 输出:4
    --it; // 现在it又指向5
    cout << *it << endl; // 输出:5

    // 测试比较操作符
    if (it != rend) 
        cout << "it is not equal to rend" << endl;
    return 0;
}

这部分代码整体不难理解,不再赘述。

反向迭代器,以及模拟实现stringvectorlist的反向迭代器的代码详细实现:Project1_list · 比奇堡的Zyb/每日学习 - 码云 - 开源中国 (gitee.com)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大话设计模式——7.抽象工厂模式(Abstract Factory Pattern)

1.介绍 抽象工厂模式是工厂模式的进一步优化&#xff0c;提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无需指定它们具体的类。属于创建型模式。 UML图&#xff1a; 2.示例 车辆制造工厂&#xff0c;不仅可以制造轿车也可以用来生产自行车。 1&#xff09;Abs…

基于Java+SpringBoot+vue+element实现校园闲置物品交易网站

基于JavaSpringBootvueelement实现校园闲置物品交易网站 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 ** 作者主页 央顺技术团队** 欢迎点赞 收藏 ⭐留言 文末获取源码联系方式 文章目录 基于…

掘根宝典之C++普通迭代器和反向迭代器详解

简介 迭代器是一种用于遍历容器元素的对象。它提供了一种统一的访问方式&#xff0c;使程序员可以对容器中的元素进行逐个访问和操作&#xff0c;而不需要了解容器的内部实现细节。 C标准库里每个容器都定义了迭代器&#xff0c;这迭代器的名字就叫容器迭代器 迭代器的作用类…

10、MongoDB -- MongoDB 的 MongoTemplate 的功能和用法介绍

目录 MongoTemplate 的功能和用法演示前提&#xff1a;登录单机模式的 mongodb 服务器命令登录【test】数据库的 mongodb 客户端命令登录【admin】数据库的 mongodb 客户端命令 为 MongoDB 提供的两个 Starterspring-boot-starter-data-mongodb&#xff08;为以同步方式操作 Mo…

Jmeter —— jmeter对图片验证码的处理!

jmeter对图片验证码的处理 在web端的登录接口经常会有图片验证码的输入&#xff0c;而且每次登录时图片验证码都是随机的&#xff1b;当通过jmeter做接口登录的时候要对图片验证码进行识别出图片中的字段&#xff0c;然后再登录接口中使用&#xff1b; 通过jmeter对图片验证码…

第N4周:中文文本分类-Pytorch实现

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营](https://mp.weixin.qq.com/s/rbOOmire8OocQ90QM78DRA) 中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制](https://mtyjkh.blog.csdn.net/)** # -*- coding: utf-8 -…

IDEA编译安卓源码TVBox(2)

一、项目结构&#xff1a;主要app和player app结构 二、增加遥控器按键选台 修改LivePlayActivity.java 1、声明变量 public String channelId "";public Timer timer new Timer();public Toast mToast;2、定义方法 private void mToastShow(String s){mToast …

攻防世界-misc-Make-similar

题目链接&#xff1a;攻防世界 (xctf.org.cn) 下载得到ogg文件。Olympic CTF 2014原题有提示120 LPM&#xff0c;对应Radiofax。需要将ogg格式文件转换成wav格式音频后&#xff0c;用OS X下的软件Multimode转换成单色传真图像&#xff1a; 文字部分为&#xff1a; section 1 of…

107. 如何使用Docker以及Docker Compose部署Go Web应用

文章目录 一、为什么需要Docker&#xff1f;二、Docker部署示例1. 准备代码2. 创建Docker镜像3. 编写Dockerfile4. Dockerfile解析5. 构建镜像6. 通过镜像创建容器运行 三、分阶段构建示例四、附带其他文件的部署示例五、关联其他容器六、Docker Compose模式七、总结 本文将介绍…

PlayBook 详解

4&#xff09;Playbook 4.1&#xff09;Playbook 介绍 PlayBook 与 ad-hoc 相比&#xff0c;是一种完全不同的运用 Ansible 的方式&#xff0c;类似与 Saltstack 的 state 状态文件。ad-hoc 无法持久使用&#xff0c;PlayBook 可以持久使用。 PlayBook 剧本是 由一个或多个 “…

5分钟上手Python爬虫:从干饭开始,轻松掌握技巧

很多人都听说过爬虫&#xff0c;我也不例外。曾看到别人编写的爬虫代码&#xff0c;虽然没有深入研究&#xff0c;但感觉非常强大。因此&#xff0c;今天我决定从零开始&#xff0c;花费仅5分钟学习入门爬虫技术&#xff0c;以后只需轻轻一爬就能查看所有感兴趣的网站内容。广告…

Docker 安装部署 ORACLE 11g数据库

Docker 安装部署 ORACLE 11g数据库 背景&#xff1a; ​ 最新在开发数据中台数据接入模块&#xff0c;其中设计很多数据类型&#xff0c;包括ORACLE &#xff0c;因为是测试使用&#xff0c;想着快速部署测试&#xff0c;于是使用Docker 部署 Oracle , 生产环境不建议使用Doc…

【LeetCode热题100】160. 相交链表(链表)

一.题目要求 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数…

鸿蒙Next学习-Flex布局

Entry Component struct FlexCase {build() {//需要在构造参数上传Flex({ direction: FlexDirection.Row,justifyContent:FlexAlign.Center }) {//flex布局Row().width(100).height(100).backgroundColor(Color.Red)Row().width(100).height(100).backgroundColor(Color.Yellow…

【ubuntu】安装 Anaconda3

目录 一、Anaconda 说明 二、操作记录 2.1 下载安装包 2.1.1 官网下载 2.1.2 镜像下载 2.2 安装 2.2.1 安装必要的依赖包 2.2.2 正式安装 shell 和 base 的切换 2.2.3 检测是否安装成功 方法一 方法二 方法三 2.3 其他 三、参考资料 3.1 安装资料 3.2 验证是否…

C语言函数—递归理解和练习

练习&#xff1a; 编写函数不允许创建临时变量&#xff0c;求字符串的长度。 我们看到这道题&#xff0c;第一个想到的是不是strlen int main() {char[] "bit";//[b][i][t][\0]//里面一共4个字符&#xff08;包括结尾的、0&#xff09;但是我们的strlen函数并不会计…

Navicat破解 Navicat下载安装 附教程 免费

百度网盘&#xff1a;https://pan.baidu.com/s/1wRRN_18_uXxPiIWCS4l43A 麻烦各位师傅帮忙填写一下问卷&#xff0c;提取码在问卷填写结束后显示~ 【https://www.wjx.cn/vm/mBBTTKm.aspx# 】 &#xff08;资料来源于网络&#xff0c;侵告删&#xff09;

‘sqlcmd‘不是内部或外部命令,也不是可运行的程序或批处理文件。

目录 一、问题 二、下载&安装sqlcmd 实用工具 三、验证 四、结果 一、问题 今天使用批处理文件执行SQLServer数据库的SQL语法时报错&#xff0c;提示sqlcmd不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。&#xff0c;发生这个问题的原因是当前系统缺少…

程序员必备开发工具、程序员必备集成开发环境(IDE)

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

大型政企寻求“智能化配方”,谁是“偏方”,谁是“验方”?

文 | 智能相对论 作者 | 叶远风 两会落幕&#xff0c;“人工智能”已成为国策&#xff0c;而全面推进智能化建设&#xff0c;大型政企首当其冲、责无旁贷——它们既是智能化转型升级的重要构成部分&#xff0c;也能直接在垂直领域形成价值引领、以点带片。 当智能成为大型政…