迭代器主要介绍
STL 迭代器是 STL 集合类(如 vectors、lists 等)的一部分。它提供一种统一的方式来访问集合中的元素。
主要有以下几种 STL 迭代器:
- 输入迭代器(Input iterator):只支持读操作,不支持修改或写入。
- 输出迭代器(Output iterator):只支持写操作,不支持读取。
- 前向迭代器(Forward iterator):支持前向遍历,只能单向访问元素。
- 双向迭代器(Bidirectional iterator):支持前向和后向遍历。
- 随机访问迭代器(Random-access iterator):支持随机访问,可以像数组那样访问。
- 环状迭代器(Circular iterator):到结尾后返回开始位置。
- 多路径迭代器(Multipass iterator):可多次遍历集合。
- 值类型迭代器(Value iterator):返回 iterator 实际持有的值。
- 插入迭代器(Insert iterator):特别用于向集合插入元素。
STL 中的集合类提供了 3 种类型的迭代器:
-
begin():返回一个指向第一个元素的迭代器。
-
end(): 返回一个迭代器,指向集合最后一个元素的下一个位置。
-
rbegin(): 返回一个指向最后一个元素的逆向迭代器。
主要作用:
- 提供统一的方式来访问 STL 集合中的元素。
- 隐藏底层集合的实现细节。
- 使 STL 算法可以在不同集合上运行。
输入迭代器
输入迭代器(Input Iterator)是最基本类型的迭代器,只支持单向遍历,并且只支持读取操作,不支持修改。
主要特点:
- 只能单向前进,不支持退格操作。
- 只支持读取操作,不支持修改元素。
- 不支持二元操作,如 ++it,it1 = it2 等。
- 不保证可重复读,一个元素可以读取多次,但读取结果不一定相同。
- 输入迭代器必须定义
++,*,->,==,!=
这些操作。
主要用途:
- 只读访问集合中的元素。
- 对集合进行过滤或统计。
STL 中使用输入迭代器的典型场景:
- find_if():查找第一个满足条件的元素。
- count():统计满足条件的元素个数。
- for_each():对每个元素执行特定函数。
- copy():将一个序列复制到另一个序列。
这些算法都只需要读访问集合元素,所以使用输入迭代器足够。
输入迭代器定义的相关操作有:
*it
:解引用,获取当前元素。- it++:移动到下一个元素。
- it == it2:判断两个迭代器是否指向同一个元素。
- it != it2:判断两个迭代器是否不同。
输出迭代器
输出迭代器(Output Iterator)是最低级的迭代器,只支持写操作,不支持读取。主要特点:
- 只支持写操作,不支持读取操作。
- 不支持二元操作,如++it 等。
- 可以多次写入同一个元素。
- 输出迭代器必须定义
++,* =
这些操作。
主要用途:
- 将元素写入某个目标。可以是文件、网络流等。
- 将元素插入集合。
常见的使用输出迭代器的算法:
- copy():复制元素到输出迭代器。
- generate():生成元素到输出迭代器。
- sort():将排序后的元素写入输出迭代器。
输出迭代器定义的操作:
*it
= x:为当前元素赋值。- it++:移动到下一个位置。
使用时,需要事先构造输出迭代器,指向目标。例如:
- 写入文件:
ofstream file("out.txt");
ostream_iterator<int> out_iter(file, " ");
- 插入集合:
vector<int> vec;
back_insert_iterator<vector<int>> vec_iter(vec);
前向迭代器
前向迭代器(Forward Iterator)支持从一个元素前进到下一个元素。主要特点:
- 支持前向遍历,不支持后退。
- 支持读写操作。可以读取和修改元素。
- 支持
++it、*it、->
等操作。 - 支持比较操作 == !=。
- 不保证可重复读。
- 可以复制迭代器。
STL 算法中使用前向迭代器:
- for_each():对每个元素执行操作
- find()/find_if():查找元素
- transform():变换每个元素
- replace():替换元素
- copy():拷贝元素
前向迭代器实现的操作符:
*it
:解引用- it++:移动到下一个元素
- it == it2:比较两个迭代器是否指向同一个元素
- it != it2:判断两个迭代器是否不同
- it = it2:迭代器赋值
与输入迭代器相比:
- 输入迭代器只支持读操作,前向迭代器同时支持读写操作
- 输入迭代器不支持复制,前向迭代器支持复制
- 前向迭代器效率略低于输入迭代器
双向迭代器
双向迭代器(Bidirectional Iterator)支持双重方向遍历,即可以前进也可以后退。
主要特点:
- 支持前向和后向遍历。
- 支持++it、–it 操作。
- 支持
== != 、*it
等操作。 - 不保证可重复读。
用于 STL 容器:
- list
- forward_list(C++11)
- deque
支持的 STL 算法:
- 常见的前向迭代器支持的算法。
- reverse():反转序列。
- unique():去除相邻重复元素。
实现的操作:
- 前向迭代器所有的操作
- –it:后退一个元素
特点总结
- 不仅支持前向遍历,还支持后向遍历。
- 相比前向迭代器,支持更多操作。
- 效率略低于前向迭代器。
随机访问迭代器
支持以下特点:
- 支持
+ - *
运算。可实现it += n; it - 3;*(it + 2)
等操作。 - 支持
[]
运算符,可以用it[n]
访问元素。 - 两个随机访问迭代器可以用 - 运算符计算间隔。
- 具备所有的双向迭代器的功能。
环状迭代器
环状迭代器(Circular Iterator)是指当迭代器到达序列的末尾时,会循环回到序列的开头。相当于一个环。
主要特点:
-
当迭代器到达末尾时,会循环回到开始位置。
-
除此以外,与 STL 标准迭代器大致相同。
-
多用于循环访问有限序列。
用途:
- 实现有限状态机。
- 循环播放音视频。
- 游戏中的循环动画。
实现方式:
-
自定义迭代器,实现环状效果。
-
使用标准迭代器和机制。
例如:
vector<int> v = {
1, 2, 3};
// 自定义迭代器
class CirIterator {
int cur;
public:
// 实现必要接口
int& operator*() {
return v[cur]; }
CirIterator& operator++() {
cur++;
if (cur >= v.size()) cur = 0;
return *this;
}
};
// 使用标准迭代器
for (auto it = v.begin(); it != v.end(); ++it) {
cout << *it;
}
cout << *v.begin(); // 打印第一个元素
多路径迭代器
多路径迭代器(Multipass Iterator)是指能够多次遍历相同的序列。
主要特点:
- 每次迭代后,迭代器位置被重新设置。
- 迭代器保持内部状态,知道序列的开始与结束位置。
- 除此以外,与 STL 标准迭代器相同。
实现方式有两种:
- 重新绑定迭代器。
iter = cont.begin(); // 重新绑定到序列开始
- 重新设置迭代器位置。
iter.reset(); // 重新设置迭代器,指向序列开始
主要用于:
- 多次对序列应用相同的操作。
- 实现可回溯的算法。
举例:
while (true) {
for (auto it = v.begin(); it != v.end(); ++it) {
// 对每个元素执行操作
}
}
值类型迭代器
值类型迭代器(Value Iterator)每次解引用返回值为元素本身,而非元素引用。
与标准迭代器的区别:
- 标准迭代器:
***(it)
返回元素的引用。 - 值类型迭代器:
*it
返回元素本身的拷贝。
主要特点:
- 当解引用时返回一个值,而非元素引用。
- 需要额外存储元素值。
- 可以像值一样访问和传递。
- 除此之外,其他与标准迭代器相似。
实现:
自定义迭代器类,实现必要接口。
例如:
class ValueIterator {
public:
ValueIterator(vector<int>::iterator iter)
: iterator(iter) {
}
int operator*() {
return *iterator;
}
// 实现其他必要接口
private:
vector<int>::iterator iterator;
};
插入迭代器
插入迭代器(Insert Iterator)
主要用于向集合中插入元素。
主要特点:
- 仅支持写入操作,不支持读取操作。
- 写入一个元素后,迭代器移动到下一位置。
- 写入元素后,原迭代器位置保持不变。
- 必须实现++和* =运算。
使用方式:
- 创建插入迭代器,指向集合。
vector<int> vec;
insert_iterator<vector<int>> iter(vec, vec.begin());
- 使用插入迭代器向集合插入元素。
*iter = 10; // 将10插入vec
++iter;
*iter = 20; // 将20插入vec
STL 中使用插入迭代器的算法:
- copy():复制元素到插入迭代器。
- generate():向插入迭代器生成元素。
- transform():转换每个元素后插入。
主要用于:
- 向集合插入元素。
- 拷贝其他集合中的元素。
- 生成元素插入集合。
通过创建插入迭代器,然后使用*it = x; ++it
;的方式向集合插入元素。
主要应用在需要插入大量元素时使用。