当前位置: 首页 > news >正文

C++教程之迭代器Iterator

前言

之前的两篇文章我们主要了解了vector和string的相关知识,从中我们知道可以通过下标来访问vector的元素或者string的字符,但是除了这种方式还有一种更为通用的方式获取元素,那就是迭代器,这篇文章就会简单介绍迭代器的相关内容。

迭代器简介

在我们使用容器去存储元素的时候有时候会需要获取存储的元素,而迭代器就是用于从容器中获取元素的,基本上所有容器的库都支持迭代器,但是只有其中一小部分支持下标获取元素的。虽然string不是容器但是其支持很多容器的操作,其中就包括下标和迭代器。

与指针类似,迭代器提供了一种间接获取对象的方式,对于迭代器而言,这个对象就是容器中的元素或者string中的字符,我们可以通过迭代器获取一个元素,与此同时也可以将指向的对象从一个对象移到下一个对象。迭代器还和指针一样有有效和无效之分,所有代表容器中元素或最后一个元素的下一个位置都是有效的,其他所有的迭代器都是无效的。

迭代器的使用

不像指针,我们不使用地址操作符去获取一个迭代器,每一个支持迭代器的类型都有函数可以返回迭代器,这些类型都有名为begin和end的函数,begin返回的是代表第一个元素的迭代器,end的返回的迭代器是容器或者字符串的最后一个元素的下一个位置,这个迭代器代表着最后一个元素的下一个位置,是一个不存在的元素。如果容器为空,则begin和end返回的是同一个迭代器。

auto b = v.begin(), e = v.end()

迭代器的操作

迭代器只支持下表列出来的操作,我们可以通过==或!=比较两个有效的迭代器,如果迭代器代表着同一个元素或者都是最后一个元素的下一个位置则相等,否则它们不等。
|操作|解释|
|*iter|返回迭代器代表的指针指向的值|
|iter->mem|等价于(*iter).mem|
|++iter|指向容器中的下一个元素|
|–iter|指向容器中的前一个元素|
|iter1 == iter2|判断两个迭代器是否相等|
|iter1 != iter2|判断两个迭代器是否不等|

对于指针,我们可以使用解引用符获取一个迭代器的元素,和指针相同,我们只能通过解引用符获取一个有效的迭代器的元素,如果解引用一个最后一个元素之后的迭代器结果是未知的。

# include<iostream>
# include<string>
using namespace std;int main() {string s("some string");if (s.begin() != s.end()) {auto it = s.begin();*it = toupper(*it);}cout<<s<<endl;}

上述的例子就是通过迭代器获取字符串s的首个字符并将其大写。

迭代器从一个元素移动到另一个元素

迭代器私用自增操作符从一个元素移动到该元素的下一个元素,自增一个迭代器与自增一个整型十分类似,对于整型而言,自增的是其本身的值,对于迭代器而言,其影响是往前进一个位置。

由于end返回的不是一个元素,所以其不能自增或者解引用

使用自增操作我们可以重写之前的程序:

# include<iostream>
# include<string>
using namespace std;int main() {string s("some string");for (auto it = s.begin(); it != s.end() && !isspace(*it); ++it) {*it = toupper(*it);}cout<<s<<endl;}

如上例所示,我们通过迭代器可以实现循环遍历。

迭代器的类型

正如我们并不准确知道vector的准确类型或者string的size,同样的,我们也不知道同时也不需要知道迭代器的准确类型,但是根据迭代器的读写权限定义了以下几种迭代器的类型:

 vector<int>::iterator it; //it可以读也可以写vector<int>的元素string::iterator it2; //it2可以读写字符串里的字符vector<int>::const_iterator it3; //it3可以读但是不可以写元素string::const_iterator it4; //it4可以读但是不可以写字符串里面的字符

const_iterator表现就像是常量指针,可以读取元素但是不能写元素

begin和end操作

begin和end返回的结果取决于它们操作的对象是不是常量,如果操作对象是常量,那么begin和end返回的就是const_iterator,如果对象不是常量,那么返回的就是iterator。

# include<iostream>
# include<string>
# include<vector>
using namespace std;int main() {
vector<int> v;
const vector<int> cv;
auto it1 = v.begin(); //it返回的是vector<int>::iterator
auto it2 = v.begin(); //it返回的是vector<int>::const_iterator
}

这种默认的返回策略有时候并不满足需求,在一些情况下一些非常量的vector我们只想读取元素,避免元素被更改,在C++11中提供了以下新的方法cbegin和cend,无论vetor是不是常量都返回const_iterator。

auto it3 = v.cbegin();

迭代器的数学运算

处理之前提到自增和自减外,迭代器还支持以下数学运算,虽然迭代器是没有下标的概念的,但是一下运算都可以理解为是对于下标的操作,如加减就是自增和自减的普通形式,就是向前移动或者向后移动,大小比较就是前后位置的比较。

操作解释
iter + n同一个容器向前移动n
iter - n同一个容器向后移动
iter1 += n将移动结果赋值给iter1
iter1 -= n将移动结果赋值给iter1
>, >=, <, <=相对位置的比较

这么说起来可能又带你抽象,下面用一个二分法来说明:

# include<iostream>
# include<string>
# include<vector>
using namespace std;int main() {vector<int> v = {1, 2, 3, 4, 5};auto beg = v.begin(), end = v.end();auto mid = v.begin() + (end - beg) / 2;int target = 2;while (mid != end && *mid != target){if (target < *mid) {end = mid;} else{beg = mid;}mid = beg + (end - beg) / 2;}cout<<to_string(*mid)<<endl;}

以上例子会打印2,也就是元素2的位置。

最后

这篇文章主要介绍了C++中的迭代器,更多文章可以关注公众号QStack。

http://www.lryc.cn/news/14438.html

相关文章:

  • 容联七陌:ChatGPT大模型能力为智能客服带来新方向
  • 【Linux 多线程同步】使用同步和互斥实现生产消费模型
  • 【TypeScript】TypeScript的接口和对象类型(interface):
  • 7、函数与异常
  • Julia 语言环境安装
  • 5.1 线程
  • 通讯录的实现
  • Urho3D导航
  • 【学习总结】激光雷达与相机外参标定:代码(cam_lidar_calibration)
  • 车载技术开发—{Android CarFrameWork}
  • 多城市二手车买卖发布管理小程序开发
  • 企业级信息系统开发学习笔记1.2 初探Spring——利用组件注解符精简Spring配置文件
  • 37、基于51单片机乒乓球比赛系统设计
  • VMware虚拟机安装Win11最详细过程以及遇到的这台电脑无法运行Windows11的问题
  • centos误删python2后怎么重新安装
  • Qt 开发使用VSCode 笔记2
  • 查找算法复习
  • 腾讯前端必会面试题(必备)
  • 探访上汽通用武汉奥特能超级工厂
  • 【Linux】线程函数和线程同步详细整理(金针菇般细)
  • Python学习笔记6:抽象
  • 自己手写一个redux
  • mysql调优参数
  • JavaEE简单示例——再插入的同时获取插入的主键列
  • sql语句练习
  • 广州蓝景—结合chatGPT下的教育模式变化
  • 大数据框架之Hadoop:MapReduce(三)MapReduce框架原理——shuffle机制
  • 4|无线传感器网络与应用|无线传感器网络原理及方法-许毅版|第3章:无线传感器网络通信-3.1协议结构 3.2物理层|青岛科技大学|课堂笔记
  • 关机时,如何控制systemd服务的关闭顺序
  • 关于MySQL镜像构建过程中添加自动初始化数据库