掘根宝典之C++迭代器简介

在C++中,容器是一种用于存储和管理数据的数据结构。C++标准库提供了多种容器,每种容器都有其独特的特点和适用场景。

我们知道啊,我们可以通过下标运算符来对容器内的元素进行访问,但是只有少数几种容器才同时支持下标运算符([ ]),因此我们需要一个更通用的机制来帮我们实现对容器内元素的访问

简介

迭代器是一种用于遍历容器元素的对象。它提供了一种统一的访问方式,使程序员可以对容器中的元素进行逐个访问和操作,而不需要了解容器的内部实现细节。

C++标准库里每个容器都定义了迭代器

迭代器的作用类似于指针,可以指向容器中的某个元素,并通过操作迭代器来访问和操作该元素。通过迭代器,我们可以实现对容器的遍历、查找、修改等操作,大大增强了程序的灵活性和通用性。

迭代器的五种类型

在C++中,迭代器按照功能和特性可以分为五种类型:

  1. 输入迭代器(Input Iterator):只能读取容器中的元素值,且只能单向移动,不支持修改元素。可以使用++操作符前进,但不能使用--操作符后退。

  2. 输出迭代器(Output Iterator):只能写入容器中的元素值,且只能单向移动,不支持读取元素。可以使用++操作符前进,但不能使用--操作符后退。

  3. 正向迭代器(Forward Iterator):支持读取和修改容器中的元素值,且可以单向移动。可以使用++操作符前进,但不能使用--操作符后退。

  4. 双向迭代器(Bidirectional Iterator):支持读取和修改容器中的元素值,且可以双向移动。可以使用++和--操作符前进和后退。

  5. 随机访问迭代器(Random Access Iterator):支持读取和修改容器中的元素值,且可以随机访问容器中的元素。可以使用++、--、+、-、[]等操作符进行前进、后退和随机访问。

这些迭代器类型提供了不同级别的功能和灵活性,可以根据具体需求选择合适的迭代器类型。通常来说,使用更高级别的迭代器可以获得更多的功能和性能,但也需要考虑容器类型支持的迭代器类型。

注意:各种迭代器的类型都不是确定的,只是一种概念性描述。它们都有一个共同的名字iterator或者const_iterator,这个我们下面会讲到

begin()成员和end()成员 

和指针不一样的是,迭代器不是使用取地址符,有迭代器的类型同时拥有返回迭代器的成员

在C++中,容器的end()函数返回一个迭代器,指向容器中的最后一个元素的下一个位置。而begin()函数返回一个迭代器,指向容器中的第一个元素的位置。

在使用迭代器遍历容器时,通常会将begin()函数返回的迭代器作为起始位置,将end()函数返回的迭代器作为结束位置。遍历过程中,迭代器会从起始位置逐个前进到结束位置,直到到达结束位置为止。

例如,对于一个vector<int>容器,可以使用迭代器来遍历其中的元素:

vector<int> vec = {1, 2, 3, 4, 5};

for (auto it = vec.begin(); it != vec.end(); ++it) {
    cout << *it << " ";
}
cout << endl;

在这个例子中,vec.begin()返回一个迭代器,指向第一个元素1的位置,vec.end()返回一个迭代器,指向最后一个元素5的下一个位置。循环中,首先将迭代器从起始位置1依次移动到2、3、4、5,最后到达结束位置,输出结果为

1 2 3 4 5

需要注意的是,end()函数返回的迭代器实际上指向了容器的末尾,并不指向容器中的最后一个元素。这是一个常见的迭代器设计约定。

迭代器类型

有迭代器的容器类型使用iterator和const_iterator类型来表示迭代器的类型

我们可以看个例子

vector<int>::iterator it1;
//it1能读取和修改vector<int>的元素

string::iterator it2;
//it2能读取和修改string的元素


vector<int>::const_iterator it3;
//it3能读取vector<int>的元素,不能修改string的元素

string::const_iterator it4;
//it4能读取string的元素,不能修改string的元素

const_iterator的对象和常量指针差不多,能读取但是不能修改它所指元素的值。相反,iterator的对象可读可写。

如果vector和string对象是个常量,只能使用const_iterator;

如果vector和string对象不是常量,则既可以使用iterator也可以使用const_iterator

begin和end运算符的返回类型

begin和end运算符的返回类型取决于调用它的这个对象是否是常量

如果对象是常量,begin和end返回const_iterator,如果对象不是常量,begin和end返回iterator

vector<int> a;
const vector<int> cv;
auto it1=v.begin();
auto it2=cv.begin();

我们可以看到it1的类型是vector<int>::iterator,it2的类型是vector<int>::const_iterator 

cbegin()和cend()函数——常量迭代器

为了便于专门得到const_iterator类型的返回值,C++11引入了两个新函数:cbegin()和cend()函数,

我们看看

vector<int> v;
auto it3=v.cbegin();

可以看到啊,it3是const_iterator类型 

我们来详细介绍一下它们两个

在C++中,容器类提供了两个函数,即cbegin()和cend()函数,用于获取一个常量迭代器的起始和结束位置。

  1. cbegin()函数返回一个指向容器中第一个元素的常量迭代器。这个迭代器只能用于读取元素的值,不能修改容器的内容。如果容器为空,cbegin()函数将返回一个指向末尾的常量迭代器。

  2. cend()函数返回一个指向容器中最后一个元素之后位置的常量迭代器。这个迭代器只能用于判断循环结束的条件,不能访问迭代器指向的元素的值。

这两个函数适用于所有标准容器,如vector、list、set等,并且它们返回的迭代器类型都是const_iterator。

常见的用法是在for循环中使用cbegin()和cend()函数来遍历容器中的元素,例如:

std::vector<int> vec = {1, 2, 3, 4, 5};

for (auto it = vec.cbegin(); it != vec.cend(); ++it) {
    std::cout << *it << " ";
}

注意:在使用cbegin()和cend()函数获取到的常量迭代器时,不能通过迭代器修改容器的值,只能读取元素的值。如果需要修改容器的值,需要使用普通迭代器,而不是常量迭代器。

使用迭代器

在C++中,可以使用迭代器来遍历容器中的元素。以下是使用迭代器的一般步骤:

  1. 定义一个迭代器变量,将其初始化为容器的起始位置。例如:

    vector<int> vec = {1, 2, 3, 4, 5};
    vector<int>::iterator it = vec.begin();
    

  2. 使用迭代器来访问容器中的元素。可以使用解引用操作符*来获取迭代器指向的元素值。例如:

    cout << *it << endl;  // 输出第一个元素的值
    

  3. 可以使用++操作符将迭代器前进到容器的下一个元素。例如:

    ++it;  // 前进到下一个元素
    

  4. 可以使用循环结构(如while、for)和条件判断来遍历整个容器。例如:

    for (vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl;
    

    或者使用基于范围的for 循环:

    for (int element : vec) {
        cout << element << " ";
    }
    cout << endl;
    

在使用迭代器遍历容器时,需要注意以下几点:

  • 使用迭代器需要包含头文件<iterator>
  • 复制容器的迭代器可以使两个迭代器指向相同的位置。
  • 不能在迭代器失效的情况下使用迭代器,例如在插入或删除元素后。

迭代器运算符 

在C++中,迭代器提供了一些运算符来对迭代器进行操作和访问容器中的元素。以下是常用的迭代器运算符:

  1. 解引用运算符(*):用于获取迭代器指向位置的元素值。例如,*it 表示获取迭代器 it 指向位置的元素值。

  2. 自增运算符(++):用于将迭代器向前移动一个位置。例如,++it表示将迭代器 it 向前移动一个位置。

  3. 自减运算符(--):用于将迭代器向后移动一个位置。例如,--it表示将迭代器 it 向后移动一个位置。

  4. 箭头运算符(->):用于获取迭代器指向位置的成员变量或成员函数。例如,it->member 表示获取迭代器 it 指向位置的成员变量或成员函数。

  5. 等于运算符(==)和不等于运算符(!=):用于比较两个迭代器是否指向同一个位置。例如,it1 == it2 表示判断迭代器 it1 和 it2 是否指向同一个位置。

  6. 大于运算符(>)、小于运算符(<)、大于等于运算符(>=)和小于等于运算符(<=):用于比较两个迭代器指向位置的相对顺序。例如,it1 > it2 表示迭代器 it1 指向位置在迭代器 it2 指向位置之后。

需要注意的是,不是所有运算符对所有类型的迭代器都可用。有些运算符只适用于双向迭代器或随机访问迭代器,而不适用于单向迭代器。

迭代器的算术运算

在C++中,一些迭代器支持算术运算符,这些运算符可以用于在迭代器上进行加法和减法操作。这些运算符包括:

  1. 加法运算符(+):用于将迭代器向前移动指定的步数。例如,it + n 表示将迭代器 it 向前移动 n 个位置。

  2. 减法运算符(-):用于将迭代器向后移动指定的步数,或者计算两个迭代器之间的距离。例如,it - n 表示将迭代器 it 向后移动 n 个位置,it1 - it2 表示计算迭代器 it1 和 it2 之间的距离。

需要注意的是,不是所有类型的迭代器都支持算术运算符。只有随机访问迭代器支持算术运算符,而单向迭代器和双向迭代器不支持算术运算符。在使用算术运算符之前,应该确保迭代器的类型是随机访问迭代器。

此外,还有一些其他的运算符可以与迭代器一起使用,如赋值运算符(=)、复合赋值运算符(+=、-=)等。这些运算符可以用于更新迭代器的位置或将一个迭代器赋值给另一个迭代器。

需要注意的是,在进行算术运算时,应该确保迭代器不超出容器的边界。否则,可能会导致未定义的行为或错误。在使用迭代器进行算术运算时,应该始终谨慎处理边界情况,并确保迭代器始终指向有效的位置。

插入迭代器

如果有一个容器,我们预先不知道它的长度,如果要把元素添加到这个容器中,而不是覆盖已有内容,那该怎么办呢?接下来就要使用到插入迭代器了。这三者都需要头文件<iterator>

back_insert_iterator

back_insert_iterator是一个插入迭代器适配器,用于在容器的末尾插入元素。它的用法如下:

  1. 创建back_insert_iterator对象并绑定到容器:
std::back_insert_iterator<std::vector<int>> backIt(vec);

这里我们创建了一个back_insert_iterator对象backIt,并将它绑定到一个std::vector&lt;int>容器vec上。通过这个back_insert_iterator对象,我们可以向vec插入元素。

  1. 使用插入迭代器插入元素:
*backIt = 6;
backIt++;
*backIt = 7;
backIt++;
*backIt = 8;

我们可以通过解引用操作符*来访问插入迭代器对应的容器,并将值赋给它。然后,使用递增操作符++来移动插入迭代器的位置。这样,我们就可以在容器的末尾依次插入元素。

  1. 使用实例:
std::vector<int> vec;
std::back_insert_iterator<std::vector<int>> backIt(vec);

*backIt = 1;    // 插入元素1
backIt++;
*backIt = 2;    // 插入元素2
backIt++;
*backIt = 3;    // 插入元素3

// 另一种更简洁的写法
std::vector<int> vec2;
std::back_insert_iterator<std::vector<int>> backIt2(vec2);

std::fill_n(backIt2, 5, 42);   // 在vec2末尾插入5个值为42的元素

需要注意的是,back_insert_iterator是一个输出迭代器,只能用于写入操作,不能用于读取元素。

此外,它只能用于支持push_back操作的容器,比如std::vectorstd::list等。

insert_iterator

insert_iterator是STL中的一个插入迭代器适配器,用于在容器的任意位置插入元素。它的用法如下:

  1. 创建insert_iterator对象并绑定到容器以及插入位置:
std::insert_iterator<std::vector<int>> insertIt(vec, vec.begin());

这里我们创建了一个insert_iterator对象insertIt,并将它绑定到一个std::vector&lt;int>容器vec上,同时指定插入位置为vec.begin()。通过这个insert_iterator对象,我们可以在指定位置插入元素。

  1. 使用插入迭代器插入元素:
*insertIt = 6;
insertIt++;
*insertIt = 7;
insertIt++;
*insertIt = 8;

我们可以通过解引用操作符*来访问插入迭代器对应的容器,并将值赋给它。然后,使用递增操作符++来移动插入迭代器的位置。这样,我们就可以在指定位置插入元素。

  1. 使用实例:
std::vector<int> vec;
std::insert_iterator<std::vector<int>> insertIt(vec, vec.begin());

*insertIt = 1;    // 在vec的开始位置插入元素1
insertIt++;
*insertIt = 2;    // 在vec的第二个位置插入元素2
insertIt++;
*insertIt = 3;    // 在vec的第三个位置插入元素3

// 另一种更简洁的写法
std::vector<int> vec2;
std::insert_iterator<std::vector<int>> insertIt2(vec2, vec2.begin());

std::fill_n(insertIt2, 5, 42);   // 在vec2的开始位置插入5个值为42的元素

需要注意的是,insert_iterator是一个输出迭代器,只能用于写入操作,不能用于读取元素。此外,它可以用于支持insert操作的容器,比如std::vectorstd::list等。

front_insert_iterator

front_insert_iterator是一个迭代器适配器,可以用于在容器的前端插入元素。它是C++标准库的一部分,可以用于修改向量、列表和双端队列等容器。

要使用front_insert_iterator,需要包含<iterator>头文件:

#include <iostream>
#include <iterator>
#include <vector>

int main() {
    std::vector<int> myVector;
    std::front_insert_iterator<std::vector<int>> frontIt(myVector);

    *frontIt = 1;  // 在向量的前端插入1
    frontIt++;    // 迭代器前进

    // 或者,可以直接使用insert函数插入元素
    frontIt = std::insert_iterator<std::vector<int>>(myVector, myVector.begin(), 2);

    // 打印向量
    for (const auto& element : myVector) {
        std::cout << element << " ";
    }
    std::cout << std::endl;

    return 0;
}

在这个例子中,我们创建了一个名为myVectorstd::vector&lt;int>向量,以及一个名为frontItfront_insert_iterator迭代器。我们使用frontIt迭代器向向量中插入元素。

*frontIt = 1语句在向量的前端插入值1frontIt++语句将迭代器前进到下一个位置。

另外,你也可以使用insert_iterator(container, iterator, value)的语法,其中container是要修改的容器,iterator是要插入值的位置,value是要插入的值。

在代码中的frontIt = std::insert_iterator&lt;std::vector&lt;int>>(myVector, myVector.begin(), 2)一行中演示了这种用法。

最后,我们打印出向量的元素,以验证结果。输出将是:

2 1

这表明通过front_insert_iterator成功地在向量的前端插入了元素。

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

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

相关文章

Leetcode 3.12

leetcode hot 100 链表1.两两交换链表中的节点2.随机链表的复制3.排序链表 链表 1.两两交换链表中的节点 两两交换链表中的节点 1.必须要设置一个dummy (temp) 结点2.保存第二个节点3.先让第一个节点指向第三个节点4.再让第二个节点指向第一个节点5.最后让dummy指向第二个节点…

2024 年 2 月 NFT 行业动态:加密货币飙升,NFT 市场调整

作者&#xff1a;stellafootprint.network 数据来源&#xff1a;NFT 研究页面 - Footprint Analytics 2024 年 2 月&#xff0c;加密货币与 NFT 市场显现出了复杂性。该月&#xff0c;NFT 领域的交易量达到 12 亿美元&#xff0c;环比下降了 3.7%。值得关注的是&#xff0c;包…

AI智能分析网关V4将HTTP消息推送至安防监控视频汇聚EasyCVR平台的操作步骤

TSINGSEE青犀视频智能分析网关V4内置了近40种AI算法模型&#xff0c;支持对接入的视频图像进行人、车、物、行为等实时检测分析&#xff0c;上报识别结果&#xff0c;并能进行语音告警播放。硬件管理平台支持RTSP、GB28181协议、以及厂家私有协议接入&#xff0c;可兼容市面上常…

从根到叶:深入了解Map和Set

窗间映出一片高远的天空&#xff0c; 向晚的天际宁静而又清明。 我孤独的心灵在幸福地哭泣&#xff0c; 它在为天空如此美好而高兴。 恬静的晚霞一片火红&#xff0c; 晚霞灼烧着我的热情。 此刻的世界没有别人&#xff0c; 只有上帝&#xff0c;我和天空。 ——&#x…

利用“定时执行专家”软件的25种任务与12种触发器,提升IT系统管理自动化水平

在IT系统管理中&#xff0c;自动化是提高工作效率、减少人为错误的关键。而《定时执行专家》这款软件&#xff0c;以其强大的功能、易用性和毫秒级的执行精度&#xff0c;成为了IT系统管理员的得力助手。今天&#xff0c;我们就来探讨一下如何利用这款软件的25种任务类型和12种…

【AI绘画】AI绘画免费网站推荐

人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是指一种模拟人类智能的技术。它是通过计算机系统来模拟人的认知、学习和推理能力&#xff0c;以实现类似于人类智能的行为和决策。人工智能技术包含多个方面&#xff0c;包括机器学习、深度学习、自…

unity3d Animal Controller的动物组件使用明天继续

控制器介绍 动物脚本负责控制动物的所有运动逻辑.它管理所有的动画师和刚体参数,以及所有的状态和模式,动物可以做。 动物控制器 是一个动画框架控制器,根动或到位,为任何生物或人形。它利用刚体与物理世界的互动和动画师的玩动画。 States States 是不互相重叠的动画。例如…

Android Kotlin知识汇总(三)Kotlin 协程

Kotlin的重要优势及特点之——结构化并发 Kotlin 协程让异步代码像阻塞代码一样易于使用。协程可大幅简化后台任务管理&#xff0c;例如网络调用、本地数据访问等任务的管理。本主题介绍如何使用 Kotlin 协程解决以下问题&#xff0c;从而让您能够编写出更清晰、更简洁的应用代…

Docker进阶:深入了解容器数据卷

Docker进阶&#xff1a;深入了解容器数据卷 一、前言二、容器数据卷的作用三、容器数据卷的使用方法四、实战--使用docker部署前端项目&#xff08;数据卷挂载&#xff09;4.1 重要&#xff1a;准备工作&#xff0c;先在本地创建挂载目录4.2 启动一个临时的nginx容器&#xff0…

vscode使用npm命令无反应,而终端可以的解决办法

如若你遇到这种情况 使用命令 get-command npm 去下面这个路径把它删掉就可以了

初识Spring MVC

什么是Spring MVC? 官方给的解释是 Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架&#xff0c;从⼀开始就包含在 Spring 框架中。它的 正式名称“Spring Web MVC”来⾃其源模块的名称(Spring-webmvc)&#xff0c;但它通常被称为"Spring MVC" 注:Severlet是…

离线下载的pytorch/torchvision/torchaudio

链接&#xff1a;https://download.pytorch.org/whl/torch_stable.html 下载pytorch-torchvision-torchaudio等一系列一定要版本匹配&#xff0c;并且如果是在gpu上跑的话&#xff0c;一定要都是cu版本 参考链接&#xff1a;https://blog.csdn.net/AiTanXiing/article/detail…

C语言 ——关键字

关键字&#xff1a;在C语言中被赋予了特定含义的英文单词&#xff0c;一共有32个关键字 * 关键字全部小写 * 在特定的编译器中&#xff0c;关键字是高亮显示的 vs&#xff1a;蓝色或者紫色 vs&#xff1a;蓝色 下图圈起来的都是关键字 c auto break case char const con…

Codeforces Round 933 (Div. 3) --- G. Rudolf and Subway --- 题解

G. Rudolf and Subway&#xff1a; 题目大意&#xff1a; 思路解析&#xff1a; 这道题很容易看出是一个最短路的图论问题&#xff0c;但是Java普通最短路常数有点高会被卡。 因为他是地铁线路&#xff0c;线路一定是一直连着的&#xff0c;不会中间断开&#xff0c;那我们可以…

Android Studio开发项目——记账簿应用

项目资源&#xff1a; 百度网盘链接&#xff1a;https://pan.baidu.com/s/1zN9lrIypi1t_QpuoBcdBNQ?pwdxj5h 提取码&#xff1a;xj5h 项目设计内容 1.基本功能描述 电子记账本是一种在线财务管理工具&#xff0c;用于帮助用户记录和管理他们的收入与支出。以下是电…

行业突破!四信实现低延时摄像头弱网状态100ms以内实时传输

随着人工智能、大数据、区块链等技术在城市中快速发展&#xff0c;人们日常生活中已经离不开网络的支撑&#xff0c;而实现“人与人”、“人与物”及“物与物”之间高速连接应用的“时延”&#xff0c;是网络支撑中最重要的存在。 以城市生活例子为例&#xff0c;当网络延时出现…

刷题日记——16进制不进位加法(厦门大学机试)

例题 分析 输入 本题解题关键在于输入的两个数位数不同时候需要尾数对齐&#xff0c;由于是16进制输入&#xff0c;含有字母&#xff0c;需要当作字符串输入&#xff0c;当然输出也要字母&#xff0c;那么就需要我们的两个老伙计了&#xff0c;一个是map&#xff0c;另一个是…

第五篇【传奇开心果系列】Python的自动化办公库技术点案例示例:深度解读Pandas在教育数据和研究数据处理领域的应用

传奇开心果博文系列 系列博文目录Python的自动化办公库技术点案例示例系列 博文目录前言一、Pandas 在教育和学术研究中的常见应用介绍二、数据清洗和预处理示例代码三、数据分析和统计示例代码四、数据可视化示例代码五、时间序列分析示例代码六、数据导入和导出示例代码七、数…

搜维尔科技:工作室选择 OptiTrack 进行新的虚拟制作舞台

35North Studios 成立于 2020 年&#xff0c;是一家最先进的制作工作室。他们的全方位服务方法可帮助电影制片人和企业在一个设备齐全且先进的地点规划、拍摄、编辑、评分和完成项目。该工作室位于爱荷华州克利尔湖&#xff0c;为创作者提供了一个安静的空间&#xff0c;让他们…

就业班 2401--3.12 Linux Day16 PXE布置——自动化装系统

什么是PXE&#xff1f; PXE&#xff0c;全名Pre-boot Execution Environment&#xff0c;预启动执行环境&#xff1b;通过网络接口启动计算机&#xff0c;不依赖本地存储设备&#xff08;如硬盘&#xff09;或本地已安装的操作系统&#xff1b;由Intel和Systemsoft公司于1999年…