五、迭代器
标签(空格分隔): c++STL
1. 迭代器及其特性
- 迭代器本身就是一种对象
- 迭代器不是通用指针,而是指向数组的指针概念的抽象
- 迭代器就是一个指示器
- 迭代器能够使程序反复得对stl容器内容进行访问,当参数化类型为c++内部类型的时候,迭代器是c++的指针。
每种容器都支持某种类别的迭代器,类别有:
输入:为程序需要数据源提供接口,数据源可以是容器,数据流等,输入迭代器只能从一个序列读入数据,此类迭代器可以被修改,引用并进行比较。
输出: 用于输出程序中得到的结果,输出迭代器只能向一个序列输出数据,此类迭代器可以被修改和引用。
前向:可以随意访问序列中的元素,可以用来读,也可写。并能保存迭代器的值,以便重新从原先位置开始遍历。
双向: 能够读写,也可被增值和减值,同时进行前向和逆向操作,所有stl都提供双向迭代器;
- 随机访问: 可以通过跳跃的方式访问容器中的任意数据,访问数据灵活。具有双向迭代器所有功能,冰球能使用算法和所有迭代器的比较功能。
迭代器的关键属性:
- 当前被指向的元素: 用“*”或“->”表示:
- 指向下一个元素: 迭代器使用增量运算符:++``
==`
- 相等,使用运算符
- 只有随机迭代器可以通过加减整数,取得相对地址;
- 除了输出迭代器之外,可以获得任意两个迭代器的距离(使用distance函数)
2.头文件简述
所有的容器都定义其各自的迭代器,不需要包含专门的头文件。
但是,逆向迭代器包含在头文件<iterator>
之中
1. 迭代器类型详述
- 迭代器是一种“能够遍历某个序列所有元素”的对象。
- 迭代器是抽象概念,只要行为类似迭代器,就是一种迭代器
迭代器的层次结构为:
A[Random access]-->B(Bidirectional)
B-->C[Forward]
C-->D[input]
C-->E[Output]
Input迭代器:用于向前读取
Output迭代器: 用于向前写入
Forward迭代器: 用于读取和写入;
Bidirectional迭代器: 双向迭代器用于前后读取写入;
Random access 迭代器: 随机存取 ,用于读取写入
1.输入型迭代器(InputIterator)
- 只能一次次地向前读取元素,并按照顺序传回元素值。
- 迭代器只能读取元素一次
- 如果两个输入型迭代器占用一个位置,则两者相同
输入型迭代器的操作:
*
:从迭代器中读取元素值->
:读取元素的成员++
: 代表前向步进;最好使用前置递增,性能更好==
: 判断相等!=
: 判断不等TYPE(iter)
: 赋值迭代器
2. 输出型迭代器(OutputIterator)
- 作用是将元素逐个写入。即只能逐个元素赋值。
- 不能使用输出型迭代器同一个序列进行两次遍历
- 输出型可以实现的操作有:
*
,++
和复制操作
例子:
1. “将元素写至标准输出装置”的迭代器,如果采用两个输出型迭代器,第二个字将跟在第一个字的后面,而不是覆盖;
- “插入器(inserter)”
3. 前向迭代器
前向迭代器是输入型和输出型迭代器的组合。
前向迭代器的操作;
表达式 | 效果 |
---|---|
*Iter | 取实际元素 |
Iter->number | 存取实际元素的成员 |
++Iter | 向前步进 |
Iter++ | 向前步进 |
Iter == Iter2 | 判断两个迭代器相等 |
Iter1 != Iter2 | 判断两个迭代器不等 |
TYPE() | 产生迭代器(默认构造函数) |
TYPE(Iter) | 复制迭代器 |
Iter1=Iter2 | 赋值 |
前向迭代器能多次指向同一集合的同一元素,并能多次处理同一元素;
- Output迭代器: 无需检查是否抵达尾端,可直接写入数据。不提供比较操作,不能讲Output迭代器和尾端迭代器比较。
- Forward迭代器: 在使用之前,需要确保迭代器是否有效! 在使用的时候,尽量使用begin()和end()作为循环的起始。
4.双向迭代器
双向迭代器在前向迭代器的基础上增加了回头遍历的功能。可以支持递减运算符。
新增操作:
表达式 | 效果 |
---|---|
–Iter / Iter– | 步退 |
5.随机存取迭代器
在双向迭代器的基础上增加了随机存取能力。
因此,必须增加迭代器运算操作。即可以实现迭代器加减某个偏移量,能处理距离问题,并可运用<
和>
等关系运算符操作。
可以支持随机存取迭代器的容器对象或数据类型有:
- vector
- deque
- strings(string,wstring)
两个string类型
- array
普通数组
随机迭代器的各项操作
表达式 | 效果 |
---|---|
Iter[n] | 存取索引位置为n的元素 |
Iter+=n | 前进n个元素 |
Iter-=n | 后退n 个元素 |
Iter+n / n+Iter | 传回iter之后的第n个元素 |
Iter-n | 传回iter之前的第n个元素 |
Iter1 - Iter2 | 判断Iter1和Iter2的距离 |
Iter1 < Iter2 | 判断iter1是否在iter2之前 |
Iter1 > Iter2 | 判断iter1 是否在iter2 之后 |
Iter1 <= Iter2 | 判断iter1是否不在iter2之后 |
Iter1 >= Iter2 | 判断iter1是否不再iter2之前 |
【注: 】随机存取迭代器对 list
和 sets
还有maps
是无效的。
6.vector迭代器的递增和递减
一般可以递增或递减暂时性容器,但是对弈vector和string容器不同;
如:
vector<int> v;
if(v.size() >1) {
sort(++v.begin(),v.end());
}
上述代码在编译的时候会出错,换成deque,就能通过编译。
原因:
1. vector 迭代器在实际操作中通常作为一般指针。c++不允许修改任何基本类型的暂时值;对于struct和class则可以;
2. 如果迭代器被实例化一般指针,编译会失败;如果迭代器被实例化class,则编译成功。deque,lists,sets和maps总能通过编译,因为这些容器的迭代器不可能被实例化为一般指针;
本内容摘抄自《c++标准程序库开发指南–不要重复造轮子》第二版
实验了一下,我在vs2013编译通过,没有出现这个问题,记录一下:不懂其中的原理。
//vs 2013
vector<int> vec2 = {9,3,3,5,2,3,1,6,7};
if (vec2.size() >1) {
sort(++vec2.begin(), vec2.end());
}
--------------省略----------------
结果为;
size: 9
vec2: 9 1 2 3 3 3 5 6 7