C++STL的迭代器(iterator)

news2024/10/6 18:33:32

一、定义

        迭代器是一种检查容器内元素并且遍历容器内元素的数据类型

        【引用自:C++迭代器(iterator)_c++ iterator_NiUoW的博客-CSDN博客】迭代器是一个变量,相当于容器和操纵容器的算法之间的中介。C++更趋向于使用迭代器而不是数组下标操作,因为标准库为每一种标准容器(如vector、map和list等)定义了一种迭代器类型,而只有少数容器(如vector)支持数组下标操作访问容器元素。可以通过迭代器指向你想访问容器的元素地址,通过*x打印出元素值。这和我们所熟知的指针极其类似。

        C语言有指针,指针用起来十分灵活高效。C++语言有迭代器,迭代器相对于指针而言功能更为丰富。

        vector,是数组实现的,也就是说,只要知道数组的首地址,就能访问到后面的元素。所以,我们可以通过访问vector的迭代器来遍历vector容器元素。
        List,是链表实现的,我们知道,链表的元素都存储在一段不是连续的地址空间中。我们需要通过next指针来访问下一个元素。那么,我们也可以通过访问list的迭代器来实现遍历list容器元素。

        由此可见,迭代器和容器是密不可分的、紧密相连的的关系。不同的容器,它们的迭代器也是不同的,但是它们的迭代器功能是一样的。假如没有迭代器,由于vector和list容器的存储特点,你需要两种算法去实现遍历vector和list容器的功能,复杂且低效。有了迭代器,遍历容器的效率会大大提高。

二、为什么要使用迭代器

         使用STL(Standard Template Library)中的迭代器有以下几个好处:

1. 统一的访问方式:STL的迭代器提供了一种统一的访问容器元素的方式,无论是数组、链表、集合还是映射,都可以通过相同的迭代器接口进行遍历和访问。这种统一性简化了代码的书写,并提高了代码的可读性和可维护性。

2. 安全的访问操作:迭代器在设计上考虑了容器的边界情况,确保不会越界访问或访问非法内存引起崩溃。迭代器提供了递增、递减等操作符,使得在容器中前进或后退一个位置变得简单和安全。

3. 灵活的遍历方式:迭代器支持正向遍历、反向遍历以及跳跃式遍历等方式,使得在不同的情况下选择合适的遍历方式变得方便。比如,可以使用反向迭代器从容器的末尾向前遍历,或者使用跳跃式迭代器按照一定规则跳过一些元素。

4. 可算法化处理:STL提供了丰富的算法,如排序、查找、拷贝、删除等,这些算法可以直接操作迭代器,而不需要关心具体容器的实现。使用迭代器作为算法的参数,使得代码可复用性更强,可以将同一套算法应用于不同类型的容器。

5. 可组合的操作:迭代器的操作是可以组合的,可以在不同的操作之间进行链式调用,形成更复杂的操作序列。这种可组合性使得代码更加灵活,可以根据需求自由组合和定制迭代器操作,实现更多样化的功能。

        总之,STL中的迭代器提供了一种抽象的、统一的访问容器元素的方式,使得我们可以以一种通用的方式处理各种不同类型的容器。这样做可以提高代码的重用性、可读性和可维护性,同时还能够充分利用STL提供的丰富算法,简化开发过程并提高效率。

另一种解释:【取自C++STL之迭代器(iterator)详解_c++迭代器-CSDN博客】

(1) STL提供每种容器的实现原理各不相同,如果没有迭代器我们需要记住每一种容器中对象的访问方法,很显然这样会变得非常麻烦。

(2) 每个容器中都实现了一个迭代器用于对容器中对象的访问,虽然每个容器中的迭代器的实现方式不一样,但是对于用户来说操作方法是一致的,也就说通过迭代器统一了对所有容器的访问方式。

(3) 迭代器的使用可以提高编程的效率。

三、迭代器的使用

3.1 基本使用方法

(1) 首先要定义一个迭代器类型变量(这里以vector容器为例)。
定义方法如下:容器类名::iterator 迭代器名;
如要定义vector容器的迭代器:vector<int>::iterator iter;(这里的iter是变量名,可以自定义)
(2) 接下来要利用迭代器访问容器数据
先要了解几个成员函数,如下表所示。

成员函数功能
begin()返回指向容器中第一个元素的正向迭代器;如果是 const 类型容器,在该函数返回的是常量正向选代器。
end()返回指向容器最后一个元素之后一个位置的正向迭代器,如果是 onst 类型容器,在该函数返回的是常量正向迭代器。此函数通常和 begin() 搭配使用。
rbegin()返回指向最后一个元素的反向迭代器,如果是 const 类型容器,在该函数返回的是常量反向迭代器。
rend()返回指向第一个元素之前一个位置的反向迭代器。如果是 const 类型容器,在该函数返回的是常量反向迭代器。此函数通常和 begin() 搭配使甲。

这里的 end()、rend() 函数要注意,不是指向容器最后一个元素,而是后一个位置(看图) 

 (3) 示例

#include<iostream>
#include<vector>

int main() {
	std::vector <int> vec; // 定义向量对象vec
	vec.push_back(2);
	vec.push_back(3);
	vec.push_back(5);
	vec.push_back(9);
	// 至此,向量vec中包含四个元素,分别是2,3,5,9

	std::vector<int>::iterator iter; // 定义迭代器类型变量iter
	iter = vec.begin(); // 变量被赋值为指向第一个元素的迭代器
	std::cout << *iter << std::endl;
	iter++; // 可以用自增操作,让iter指向下一个元素
	std::cout << *iter << std::endl;
	iter = vec.begin() + 2; // 让iter指向容器中的第三个位置
	std::cout << *iter << std::endl;
}

输出结果:
2 3 5  

注意:vector容器迭代器属于随机访问迭代器,可以一次移动多个位置,如iter=v1.begin()+2;
也可以用iter=iter+2;

3.2 容器数据的遍历

3.2.1 常见方法(正序遍历)

for (auto it = container.begin(); it != container.end(); ++it) {
    // process element *it
}

3.2.2 常见方法(逆序遍历) 

for (auto it = container.rbegin(); it != container.rend(); ++it) {
    // process element *it
}

        其中,auto是C++11的关键字,它可以自动推导迭代器类型。循环中,首先使用begin()函数获取容器起始位置的迭代器,然后每次使用递增运算符前进一个位置,直到迭代器等于end()函数返回的迭代器时结束循环。

3.2.3 注意问题 

        需要注意的是,在处理空容器或只有一个元素的容器时,begin()end()函数返回的迭代器是相同的,因此在循环中不能使用!=运算符进行比较,而应该使用    或   运算符判断是否越界。

        当一个容器为空或只有一个元素时,`begin()`和`end()`函数返回的迭代器是同一个位置,因此使用`!=`运算符进行比较可能会得到错误的结果。

        对于空容器,`begin()`和`end()`函数都返回指向末尾的迭代器,因为没有元素可以遍历。这种情况下,应该直接判断迭代器是否等于末尾迭代器,如下所示:

std::vector<int> v;
if (v.begin() == v.end()) {
    // 处理空容器的情况
}

        对于只有一个元素的容器,`begin()`和`end()`函数虽然会返回不同的迭代器,但是它们指向的是同一个位置,即容器中唯一的元素。这种情况下,应该使用`<`或`>`运算符进行比较,如下所示:

std::vector<int> v{1};
for (auto it = v.begin(); it < v.end(); ++it) { // 注意这里使用<
    std::cout << *it << std::endl;
}

        同样地,在循环中也可以使用`>=`或`<=`运算符判断是否越界,但是更好的做法是使用标准库提供的迭代器判等函数`std::equal()`、`std::lexicographical_compare()`等,这些函数会自动处理空容器和只有一个元素的容器的情况,并提供更好的可读性和代码健壮性。

3.2.4 遍历应用示例

#include<iostream>
#include<vector>

int main() {
	std::vector <int> vec; // 定义向量对象vec
	vec.push_back(2);
	vec.push_back(3);
	vec.push_back(5);
	vec.push_back(9);
	// 至此,向量vec中包含四个元素,分别是2,3,5,9

	// 遍历向量vec中的所有元素
	for (auto iter = vec.begin(); iter != vec.end(); iter++) {
		std::cout << *iter << " ";
	}
	std:: cout << std::endl;
}

注意:上面说到end()函数是指向容器的最后一个元素的后一个位置,所以当迭代器指向最后的后一个位置时结束遍历,便可以访问所有容器元素。  

输出结果:

2 3 5 9 

四、不同容器的迭代器(iterator)的功能

vector                  随机访问
deque                  随机访问
list                        双向
set / multiset        双向
map / multimap    双向
stack                    不支持迭代器
queue                  不支持迭代器
priority_queue     不支持迭代器
 

参考文献

C++STL之迭代器(iterator)详解_c++迭代器-CSDN博客
C++迭代器(iterator)_c++ iterator_NiUoW的博客-CSDN博客
关于迭代器失效的几种情况-CSDN博客(值得阅读)

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

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

相关文章

【GESP】2023年06月图形化三级 -- 自幂数判断

文章目录 自幂数判断【题目描述】【输入描述】【输出描述】【参考答案】其他测试用例 自幂数判断 【题目描述】 自幂数是指N位数各位数字N次方之和是本身&#xff0c;如153是3位数&#xff0c;其每位数的3次方之和是153本身&#xff0c;因此153是自幂数&#xff0c;1634是4位数…

STM32进行LVGL裸机移植

本文的移植参考的是正点原子的课程《手把手教你学LVGL图形界面编程》 基于该课程和《LVGL开发指南_V1.3》“第二章 LVGL 无操作系统移植”&#xff0c;然后结合自身的实际情况进行整理。 先根据自己的习惯&#xff0c;创建基础的单片机工程&#xff0c;然后在APP业务层和DRIVE…

cdm解决‘ping‘ 或者nslookup不是内部或外部命令,也不是可运行的程序或批处理文件的问题

当我们在执行cmd时&#xff0c;会出现不是内部或外部命令&#xff0c;也不是可运行的程序的提示。 搜索环境变量 点开高级 >> 环境变量 打开Path&#xff0c;看是否在Path变量值中存在以下项目&#xff1a; %SystemRoot%/system32; %SystemRoot%; %SystemRoot%/Syste…

【JVM系列】- 探索·运行时数据区的私有结构

探索运行时数据区的私有结构 文章目录 探索运行时数据区的私有结构运行时数据区的结构与概念认识线程了解守护线程和普通线程JVM系统线程 程序计数器&#xff08;PC寄存器&#xff09;概述PC寄存器的特点PC寄存器的作用 透过案例了解寄存器为什么需要用PC寄存器来存放字节码的指…

C语言基础-循环与数组

目录 循环 while 循环&#xff1a; for 循环&#xff1a; do while 循环&#xff1a; 中断循环&#xff1a; break continue&#xff1a; 数组 数组&#xff1a;用来装一组数的类型。声明形式如下&#xff1a; 定义数组类型变量&#xff1a; 下标&#xff1a;即各元素…

初出茅庐的小李博客之ESP8266获取自己B站粉丝数据

获取方式 ESP8266发起HTTP请求解析json数据 获取粉丝API: https://api.bilibili.com/x/relation/stat?vmid349513188API浏览器测试返回结果 {"code": 0,"message": "0","ttl": 1,"data": {"mid": 349513188, …

Python+Appium实现自动化测试

一、环境准备 1.脚本语言&#xff1a;Python3.x IDE&#xff1a;安装Pycharm 2.安装Java JDK 、Android SDK 3.adb环境&#xff0c;path添加E:\Software\Android_SDK\platform-tools 4.安装Appium for windows&#xff0c;官网地址 Redirecting 点击下载按钮会到GitHub的…

【safetensor】介绍和基础代码

Hugging Face, EleutherAI, StabilityAI 用的多 介绍 文件形式 header&#xff0c;体现其特性。如果强行将pickle或者空软连接 打开&#xff0c;会出现报错。解决详见&#xff1a;debug 连接到其他教程结构和参数 安装 with pip:Copied pip install safetensors with con…

阶段六-Day05-MyBatis3

一、多表查询&#xff08;面试题&#xff09; 1. 介绍 多表查询是在企业中必不可少的&#xff0c;无论多么简单的项目里通常会出现多表查询的操作。因为只要是关系型数据库&#xff0c;在设计表时都需要按照范式进行设计&#xff0c;为了减少数据冗余&#xff0c;都会拆成多个…

String、StringBuffer、StringBuilder 适合的应用场景

文章目录 String适用场景示例代码 StringBuffer适用场景示例代码 StringBuilder适用场景示例代码 性能比较总结 &#x1f389;欢迎来到Java学习路线专栏~String、StringBuffer、StringBuilder 适合的应用场景 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff…

《视觉SLAM十四讲》公式推导(二)

CH3-5 四元数表示旋转 三维空间中任意点均可用一个纯虚四元数表示即 p [ 0 , v ] T \boldsymbol{p}[0,\boldsymbol{v}]^T p[0,v]T&#xff0c;经一个单位四元数 q \boldsymbol{q} q的旋转后&#xff0c;得到 p ′ \boldsymbol{p} p′&#xff0c;则 p ′ q p q − 1 (3-5-1)…

STM32F4_中英文显示

目录 1. 液晶显示逻辑 2. 汉字显示原理 3. 实验程序 3.1 main.c 3.2 text.c 3.3 text.h 3.4 fontupd.c 3.5 fontupd.h 1. 液晶显示逻辑 字符编码&#xff1a; 由于计算机只能识别 0 和 1&#xff0c;文字也只能以 0 和 1 的形式在计算机里存储&#xff0c;所以我们需要…

算法通过村第十六关-滑动窗口|青铜笔记|滑动很简单

文章目录 前言滑动窗口的基本思想入门题目练习子数组最大平均数最长连续递增序列 总结 前言 提示&#xff1a;我宁愿做自己&#xff0c;做卑微的自己&#xff0c;也不愿做别人&#xff0c;无论那会多么快乐。 --《美丽新世界》 我们在数组和链表的部分就已经接触到了双指针的思…

IMX6ULL开发——第一个驱动程序

实现第一个应用程序&#xff1a;在IMX6ULL开发板上运行驱动程序hello_drv_test hello_drv_test #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <string.h>/** ./hel…

生产者消费者模式(c++实现)

生产者消费者模式思路就是&#xff1a;一批专门生产资源的线程 和一批专门处理资源的线程以及一个线程安全的任务队列组成的 。并且当任务队列满的时候阻塞生产线程&#xff0c;任务队列为空的时候阻塞消费线程。 要实现一个生产者消费者队列 1。需要实现线程同步&#xff0c;…

react的setState做了什么

1、为什么需要setState setState的作用是帮助我们更改数据的同时并且通知视图进行渲染。因为React并不会绑定视图和state&#xff0c;需要我们手动去更新视图。 2、setState什么时候是同步的&#xff0c;什么时候是异步的 setState这个方法在调用的时候是同步的&#xff0c;…

如果面试问到你redis的常用数据类型,你怎么和面试官聊上十分钟?

最近组长把一些简历推到我这边让我帮他面试几份&#xff0c;问到这种基础题目时收到的回答总是不太理想 1、最简单的回答&#xff1a; Redis存储的是key-value结构的数据&#xff0c;其中key是字符串类型&#xff0c;value有5种常用的数据类型&#xff1a; 字符串 string哈希 …

为什么spring默认采用单例bean

概 述 熟悉 Spring开发的朋友都知道 Spring 提供了 5种 scope&#xff0c;分别是&#xff1a; singleton: 单例模式&#xff0c;当spring创建applicationContext容器的时候&#xff0c;spring会欲初始化所有的该作用域实例&#xff0c;加上lazy-init就可以避免预处理&#xf…

磁盘分区如何分? 电脑磁盘分区免费软件指南!

列出并比较顶级免费磁盘分区管理器软件&#xff0c;以选择适用于 Windows 的最佳分区软件&#xff1a; 系统分区在现代计算机设备中起着非常重要的作用。它们可以存储数据&#xff0c;使系统文件远离用户数据&#xff0c;并在同一台设备上安装多个操作系统。但是&#xff0c;这…

MyBatis-Plus 实战教程一

这里写目录标题 简介快速上手数据库建立创建实体类修改参数引入依赖测试常见注解介绍TableNameTableIdTableField 常见配置仓库地址 简介 MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;…