细说C++反向迭代器:原理与用法
文章目录
- 一、引言
- 二、反向迭代器的原理与实现细节
- 三、模拟实现C++反向迭代器
- 反向迭代器模板类的设计
- 反向迭代器的使用示例与测试
一、引言
- 迭代器与反向迭代器的概念引入
迭代器(Iterator)是C++标准模板库(STL)中的一个核心概念,它提供了一种访问容器中元素的方式,而无需了解容器底层的实现细节。迭代器就像是一个指向容器中元素的指针,通过它可以遍历容器中的元素,进行读取、修改或删除操作。
反向迭代器(Reverse Iterator)则是迭代器的一个变种,它允许我们从后向前遍历容器中的元素。反向迭代器的出现极大地丰富了C++中容器的遍历方式,特别是在需要逆向操作容器元素时,提供了极大的便利。
- 反向迭代器在C++中的重要作用
反向迭代器在C++中扮演着至关重要的角色。在处理一些需要逆向遍历容器的场景时,如从后向前打印数组元素、逆序遍历链表节点等,使用反向迭代器可以大大简化代码逻辑,提高代码的可读性和可维护性。此外,反向迭代器还使得一些复杂的算法实现变得更加简单和直观。
本文将详细介绍C++中反向迭代器的概念、原理和使用方法,并通过模拟实现一个简单的反向迭代器来加深读者对反向迭代器的理解。通过本文的学习,读者将能够掌握反向迭代器的基本用法,并能够在实际编程中灵活运用反向迭代器来处理各种需要逆向遍历容器的场景。
二、反向迭代器的原理与实现细节
- 反向迭代器的内部机制
反向迭代器是一种特殊的迭代器,它的内部机制基于容器的正向迭代器。通常,反向迭代器在内部持有一个指向容器末尾之后位置的迭代器,或者一个指向容器第一个元素之前的迭代器,这取决于容器的具体实现。当对反向迭代器进行自增或自减操作时,它实际上是在对内部的正向迭代器进行相反的操作,从而实现从后向前的遍历。因此我们在模拟实现反向迭代器时,通常以原容器的正向迭代器为成员,所谓 reverse_iterator
,可以将迭代器的行进方向逆转,使原本应该前进的 operator++
变成了后退操作, operator--
变成了前进操作。
- 反向迭代器的设计与实现要点
设计并实现一个反向迭代器需要考虑以下几个要点:
-
迭代器类型的选择:反向迭代器需要基于某种正向迭代器进行实现。因此,首先需要确定所针对的容器类型及其对应的正向迭代器类型。
-
解引用与箭头操作符的重载:反向迭代器需要重载解引用操作符(
*
)和箭头操作符(->
),以便能够正确地访问容器中的元素。这通常涉及对内部正向迭代器的相应操作,以确保访问的是正确的元素。 -
反向遍历的实现:反向迭代器的核心功能是从后向前遍历容器。这通常通过调整正向迭代器的位置来实现。例如,在每次自增操作中,反向迭代器实际上会使内部的正向迭代器向前移动一个位置,从而模拟出从后向前的遍历效果。为了配合迭代器区间的“前闭后开”,我们通常按下图方式设计反向迭代器:
- 反向迭代器与STL容器的结合使用
在C++标准模板库中,许多容器都提供了反向迭代器的支持。例如,vector
、list
、string
等容器都提供了rbegin()
和rend()
成员函数,用于获取指向容器末尾和末尾之后位置的反向迭代器。通过这些反向迭代器,我们可以方便地实现从后向前的遍历操作。
在实际使用中,我们可以将反向迭代器与范围基于的for循环(C++11及以后版本)或传统的while循环结合使用,来处理需要逆向遍历容器的场景。反向迭代器的使用方式与正向迭代器类似,只是遍历的方向相反而已。
三、模拟实现C++反向迭代器
在C++中,反向迭代器是一种特殊的迭代器,它允许我们按照相反的顺序遍历容器中的元素。在本节中,我们将模拟实现一个通用的反向迭代器模板类,并详细解释其设计、实现以及使用示例。
反向迭代器模板类的设计
为了设计一个通用的反向迭代器模板类,我们需要考虑以下几个关键部分:
-
模板参数的选择与意义:
在
ReverseIterator
类的模板参数中,Iterator
、Ref
和Ptr
的选择和它们各自的意义如下:-
Iterator
:Iterator
是一个模板参数,它代表了正向迭代器的类型。这个类型通常是一个STL迭代器或者类似的自定义迭代器,用于遍历容器(如vector
、list
等)。在ReverseIterator
中,Iterator
类型用于内部存储,并且在进行反向遍历的时候,它将被用来模拟反向迭代的行为。 -
Ref
是另一个模板参数,用于指定operator*
的返回类型。它应该是一个引用类型,这样operator*
才能返回当前反向迭代器指向的元素的引用。返回引用允许用户直接修改通过反向迭代器访问的元素的值。
在大多数情况下,
Ref
可以简单地设置为Iterator
的value_type&
,其中value_type
是正向迭代器所指向元素的类型。例如,如果Iterator
是vector<int>::iterator
,那么Ref
就应该是int&
。Ptr
是第三个模板参数,用于指定operator->
的返回类型。它应该是一个指针类型,这样operator->
才能返回当前反向迭代器指向的元素的指针。这个指针类型通常用于通过->
操作符访问元素的成员。
同样地,
Ptr
可以设置为Iterator
的value_type*
。对于上面的vector<int>::iterator
示例,Ptr
就是int*
。template<class Iterator, class Ref, class Ptr> class ReverseIterator { public:typedef ReverseIterator<Iterator, Ref, Ptr> Self;//... }
-
-
成员变量与构造函数的实现:
-
成员变量
_it
:存储正向迭代器的实例,用于实现反向遍历。Iterator _it; // 存储正向迭代器
-
构造函数:接受一个正向迭代器作为参数,初始化成员变量
_it
。ReverseIterator(Iterator it) : _it(it) {}
-
-
反向迭代器核心操作符的重载:
- 自增与自减操作符:
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->
,并且返回的类型与Ref
和Ptr
兼容。在标准库中的迭代器类型中,这通常是成立的。但对于自定义迭代器类型,需要确保这些操作符的行为符合预期。- 比较操作符:
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指向4cout << *it << endl; // 输出:4--it; // 现在it又指向5cout << *it << endl; // 输出:5// 测试比较操作符if (it != rend) cout << "it is not equal to rend" << endl;return 0;
}
这部分代码整体不难理解,不再赘述。
反向迭代器,以及模拟实现string
、vector
、list
的反向迭代器的代码详细实现:Project1_list · 比奇堡的Zyb/每日学习 - 码云 - 开源中国 (gitee.com)
相关文章:

细说C++反向迭代器:原理与用法
文章目录 一、引言二、反向迭代器的原理与实现细节三、模拟实现C反向迭代器反向迭代器模板类的设计反向迭代器的使用示例与测试 一、引言 迭代器与反向迭代器的概念引入 迭代器(Iterator)是C标准模板库(STL)中的一个核心概念&am…...

SpringBoot(依赖管理和自动配置)
文章目录 1.基本介绍1.springboot是什么?2.快速入门1.需求分析2.环境配置1.确认开发环境2.创建一个maven项目3.依赖配置 pom.xml4.文件目录5.MainApp.java (启动类,常规配置)6.HelloController.java (测试Controller&a…...

cad怎么转换成黑白的pdf图纸?分享3个常用的软件!
在工程设计、建筑、机械制造等领域,CAD图纸的应用非常广泛。然而,有时出于某些需要,我们可能需要将CAD图纸转换为黑白的PDF格式。那么,如何实现这一转换呢?本文将为您详细介绍几种常用的转换软件及其操作步骤。 迅捷CA…...

maven本地仓库依赖上传到远程仓库
本地仓库上传到远程仓库 批量上传: 批量本地仓库依赖(jar包)上传脚本: #!/bin/bash # copy and run this script to the root of the repository directory containing files # this script attempts to exclude uploading itse…...

ISIS多区域实验简述
为支持大型路由网络,IS-IS在路由域内采用两级分层结构。 IS-IS网络中三种级别的路由设备:将Level-1路由设备部署在区域内,Level-2路由设备部署在区域间,Level-1-2路由设备部署在Level-1和Level-2路由设备的中间。 实验拓扑图&…...

go语言基础笔记
1.基本类型 1.1. 基本类型 bool int: int8, int16, int32(rune), int64 uint: uint8(byte), uint16, uint32, uint64 float32, float64 string 复数:complex64, complex128 复数有实部和虚部,complex64的实部和虚部为32位,complex128的实部…...

kettle 9.4和Pentoho 9.4下载及安装方法简介
kettle 9.4和Pentoho 9.4下载及安装方法简介 下载地址: https://sourceforge.net/projects/pentaho/files/ 下载步骤: #------------- 一、点击选项卡:summary/ 二、点击第一行链接 https://www.hitachivantara.com/en-us/products/pentaho…...

社交革命的引领者:探索Facebook如何改变我们的生活方式
1.数字社交的兴起 随着互联网的普及,社交媒体成为我们日常生活的重要组成部分。Facebook作为其中的先驱,从最初的社交网络演变成了一个拥有数十亿用户的全球化平台。它不仅改变了我们与世界互动的方式,还深刻影响了我们的社交习惯、人际关系以…...
常用的推荐算法
推荐系统在帮助用户发现可能感兴趣的产品、服务或信息方面发挥着重要作用。下面是一些常用的推荐算法: 1. 协同过滤 用户基于协同过滤(User-Based Collaborative Filtering) 基于用户之间的相似性为用户推荐物品。算法会找出与目标用户兴趣…...
使用Python进行图片格式转化/分辨率转化
一.下载python PIY插件库 PIP下载命令: pip install pillow -i https://mirrors.aliyun.com/pypi/simple PIY插件库:pillow Installation - Pillow (PIL Fork) 10.3.0.dev0 documentation 二.分辨率转化 from PIL import Image import osresolution (1024, 1024) with Image…...

植物神经功能紊乱患者每天从5片黛力新减少至2片,只因找对了治疗方法!
植物神经功能紊乱是一种常见的心理疾病,其症状包括焦虑、失眠、疲劳、头痛、胃肠不适等,给患者带来很大的困扰。然而,这种疾病是可以治疗的。本文将介绍一位植物神经功能紊乱患者的治疗经历,希望能够帮助更多的人了解和治疗此病。…...

SpringSecurity 快速入门
文章目录 1. 认证授权概述1.1 认证授权概念1.1.1 认证1.1.2 授权 1.2 权限数据模型1.3 RBAC权限模型1.3.1 介绍1.3.2 基于角色访问控制1.3.3 基于资源访问控制 1.4 常见认证方式1.4.1 Cookie-Session1.4.2 jwt令牌无状态认证 1.5 技术实现 2. SpringSecurity入门2.1 介绍2.2 入…...

MySQL--执行一条 select 语句,期间发生了什么?
执行一条 SQL 查询语句,期间发生了什么? 连接器:建立连接,管理连接、校验用户身份;查询缓存:查询语句如果命中查询缓存则直接返回,否则继续往下执行。MySQL 8.0 已删除该模块;解析 …...
DeepL:word文档导出后不能编辑
参考解决用DeepL翻译文档后不能编辑问题_deepl翻译出来的文档怎么编辑-CSDN博客 1、将deepL导出的word文档另存为.xml文件 2、将.xml文件以txt格式打开,查找内容:<w:documentProtection,删除整个标签(包括<w: ...>&…...

PCL 约束Delaunay三角网(版本二)
目录 一、算法概述二、代码实现三、结果展示四、测试数据本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法概述 PCL 点云Delaunay三角剖分一文给出了PCL中Delaunay三角网算法的基础用法。本文在基础用法的基…...

位运算#蓝桥杯
位运算#蓝桥杯 文章目录 位运算#蓝桥杯1、小蓝学位运算2、异或森林3、位移4、笨笨的机器人5、博弈论 1、小蓝学位运算 #include<bits/stdc.h> using namespace std; using LL long long; const LL N 1e97; template<int kcz> struct ModInt { #define T (*this)…...
Python yield from
yield from是Python生成器(generator)中的一个语法,用于简化生成器的操作。它可以使一个生成器委托部分操作给另一个生成器,从而简化代码。yield from在Python 3.3及更高版本中被引入。 在使用yield from之前,我们需要…...
Atcoder TUPC 2023(東北大学プログラミングコンテスト 2023)E. And DNA(矩阵快速幂+拆位讨论)
题目 长为n(3<n<1e9)的数组,第i个数ai在[0,m](m<1e9)之间 对于i∈[1,n],均满足a[i](a[i-1]&a[i1])m,求这样可能的数组的方案数 特别地,认为a[0]a[n],a[n1]a[1],即这个数组是个环形的数组 思路来源 官…...

Matlab/simulin光伏发电直流串联故障电弧模型仿真
参考文献 模型复现...

4款实用性前端动画特效分享(附在线演示)
分享4款非常不错的项目动画特效 其中有jQuery特效、canvas特效、CSS动画等等 下方效果图可能不是特别的生动 那么你可以点击在线预览进行查看相应的动画特效 同时也是可以下载该资源的 全屏图片视差旋转切换特效 基于anime.js制作全屏响应式的图片元素布局,通过左…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
区块链技术概述
区块链技术是一种去中心化、分布式账本技术,通过密码学、共识机制和智能合约等核心组件,实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点:数据存储在网络中的多个节点(计算机),而非…...

在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例
目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码:冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...

pgsql:还原数据库后出现重复序列导致“more than one owned sequence found“报错问题的解决
问题: pgsql数据库通过备份数据库文件进行还原时,如果表中有自增序列,还原后可能会出现重复的序列,此时若向表中插入新行时会出现“more than one owned sequence found”的报错提示。 点击菜单“其它”-》“序列”,…...