C++ STL 中的迭代器
迭代器是一种行为类似指针的对象,用于遍历和访问容器中的元素。
- 可以在不暴露容器内部结构的情况下进行遍历。
- 支持独立于容器的算法,如 sort()、count()、find() 等。
- 类型包括:输入迭代器、输出迭代器、前向迭代器、双向迭代器和随机访问迭代器。
- 声明方式:
container_type::iterator it;或auto it = container.begin();。
示例代码:
cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {10, 20, 30, 40};
// 使用迭代器遍历 vector
for (vector<int>::iterator it = v.begin(); it != v.end(); ++it){
cout << *it << " ";
}
return 0;
}
10 20 30 40
容器迭代器函数
STL 容器提供一系列返回迭代器的成员函数。 这些迭代器通常指向容器的首尾元素。 绝大多数 STL 容器都支持这些函数;stack、queue 等访问受限的容器除外。为保持统一,各容器中的函数名称完全一致。
容器返回迭代器的常用方法如下:
| 函数 | 说明 |
|---|---|
begin() |
返回指向容器首元素的正向迭代器。 |
end() |
返回指向容器尾元素之后位置的正向迭代器。 |
cbegin() |
返回指向容器首元素的常量正向迭代器,不可修改元素值。 |
cend() |
返回指向容器尾元素之后 位置的常量正向迭代器。 |
rbegin() |
返回指向容器首元素的反向迭代器(实际指向最后一个元素)。 |
rend() |
返回指向容器尾元素之前 位置的反向迭代器。 |
crbegin() |
返回指向容器首元素的常量反向迭代器。 |
crend() |
返回指向容器尾元素之前 位置的常量反向迭代器。 |
示例代码:
cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vec = {10, 20, 30, 40, 50};
// 正向迭代
cout << "Forward iteration: ";
for (auto it = vec.begin(); it != vec.end(); ++it){
cout << *it << " ";
}
cout << endl;
// 只读正向迭代
cout << "Forward (read-only) iteration: ";
for (auto it = vec.cbegin(); it != vec.cend(); ++it){
cout << *it << " ";
}
cout << endl;
// 反向迭代
cout << "Reverse iteration: ";
for (auto it = vec.rbegin(); it != vec.rend(); ++it){
cout << *it << " ";
}
cout << endl;
return 0;
}
yaml
Forward iteration: 10 20 30 40 50
Forward (read-only) iteration: 10 20 30 40 50
Reverse iteration: 50 40 30 20 10
迭代器操作
与指针算术类似,C++ 迭代器也支持一些操作,这些操作增强了迭代器的重要性。C++ 中共有 5 种有效的迭代器操作:
1. 解引用(Dereferencing)
解引用操作允许用户访问或修改迭代器所指向元素的值。与指针一样,使用 * 间接运算符进行解引用。
示例代码:
cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {10, 20, 30, 40};
// 迭代器指向首元素
auto it = v.begin();
// 解引用访问值
cout << "First element: " << *it << endl;
// 解引用修改值
*it = 100;
// 输出修改后的首元素
cout << "Updated first element: " << *it << endl;
return 0;
}
sql
First element: 10
Updated first element: 100
2.迭代器的自增/自减操作
我们可以使用 ++ 或 -- 运算符分别将迭代器向前或向后移动一个位置。
- 自增(
++)操作将迭代器指向容器中的下一个元素; - 自减(
--)操作将迭代器指向前一个元素。
示例代码:
cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {10, 20, 30, 40, 50};
// 迭代器指向起始位置
auto it = v.begin();
// 自增,移动到下一个元素
++it;
cout << "After increment: " << *it << endl;
// 自减,回到前一个元素
--it;
cout << "After decrement: " << *it << endl;
return 0;
}
yaml
After increment: 20
After decrement: 10
3.给迭代器加减整数
只有随机访问迭代器 (如 vector、deque 的迭代器)才支持给迭代器加上或减去一个整数,从而一次性向前或向后跳跃多个位置。
list、set、map 等容器的迭代器不支持这种算术运算。
示例代码:
cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {10, 20, 30, 40, 50};
// 迭代器指向起始位置
auto it = v.begin();
// 向前移动 2 个位置
it = it + 2;
cout << "Element after moving forward by 2: " << *it << endl;
// 向后移动 1 个位置
it = it - 1;
cout << "Element after moving backward by 1: " << *it << endl;
return 0;
}
csharp
Element after moving forward by 2: 30
Element after moving backward by 1: 20
4.迭代器相减
我们可以将一个迭代器减去另一个迭代器,从而得到它们之间相隔的元素个数(即距离)。
该操作同样仅适用于随机访问迭代器 (如 vector、deque)。
示例代码:
cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {10, 20, 30, 40, 50};
// 定义两个迭代器
auto it1 = v.begin(); // 指向 10
auto it2 = v.begin() + 3; // 指向 40
// 计算两者之间的距离
cout << "Distance between it1 and it2: " << it2 - it1 << endl;
return 0;
}
sql
Distance between it1 and it2: 3
5.迭代器比较
我们可以对同一个容器 的两个迭代器进行关系比较,以判断它们的相对位置。
可用的运算符包括:==、!=、<、>、<=、>=。
(同样,这些比较操作要求迭代器至少是随机访问迭代器 或双向迭代器。)
示例代码:
cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {10, 20, 30, 40};
// 定义两个迭代器
auto it1 = v.begin(); // 指向 10
auto it2 = v.begin() + 2; // 指向 30
// 比较迭代器
if (it1 != it2)
{
cout << "Iterators point to different elements." << endl;
}
if (it1 < it2)
{
cout << "it1 comes before it2 in the vector." << endl;
}
return 0;
}
arduino
Iterators point to different elements.
it1 comes before it2 in the vector.
C++ 迭代器类型
STL 中的迭代器可按"允许执行的操作"进行分类:
-
输入迭代器(Input Iterator)
只能顺序读取容器元素(单向一次遍历)。
支持容器如
istream_iterator;支持运算符:
*、++、==、!=。 -
输出迭代器(Output Iterator)
只能顺序写入容器元素(单向一次遍历)。
支持容器如
ostream_iterator;支持运算符:
*、++。 -
前向迭代器(Forward Iterator)
可读写 元素,并允许多次遍历。
支持容器如
forward_list、unordered_set、unordered_map;支持运算符:
*、++、==、!=。 -
双向迭代器(Bidirectional Iterator)
可在容器中前后双向移动。
支持容器如
list、set、map、multiset、multimap;支持运算符:
*、++、--、==、!=。 -
随机访问迭代器(Random Access Iterator)
可使用算术运算自由跳转到任意位置。
支持容器如
vector、deque、array;支持运算符:
*、++、--、+、-、[]、<、>、<=、>=。
迭代器适配器
C++ 中的迭代器适配器是一种基于传统迭代器构建的特殊迭代器,用于提供专门的功能。常见的迭代器适配器如下:
| 迭代器适配器类型 | 说明 |
|---|---|
| 反向迭代器(Reverse Iterator) | 基于双向或更高级迭代器构建,允许用户反向遍历容器。 |
| 流迭代器(Stream Iterators) | 包括 istream_iterator 和 ostream_iterator,分别基于输入/输出迭代器构建,可把输入/输出流当作容器使用。 |
| 移动迭代器(Move Iterators) | 在 STL 算法中引入移动语义 ,将源容器数据的所有权转移给目标容器,避免额外拷贝。 |
| 插入迭代器(Inserter Iterator) | 允许在容器的指定位置插入元素。C++ 提供三种插入迭代器: |
• back_insert_iterator:在容器尾部插入。 |
|
• front_insert_iterator:在容器头部插入。 |
|
• insert_iterator:在容器任意位置插入。 |
|
可通过 back_inserter()、front_inserter()、inserter() 函数创建。 |
C++ 迭代器工具函数
C++ STL 提供了一系列便捷函数,用于简化迭代器的使用。下表列出常用函数及其作用与语法:
| 函数 | 说明 | 语法 |
|---|---|---|
std::advance |
将迭代器向前/向后移动指定距离 | advance(it, n) |
std::next |
返回后移 n 位的新迭代器(原迭代器不变) | next(it, n) |
std::prev |
返回前移 n 位的新迭代器(原迭代器不变) | prev(it, n) |
std::distance |
计算两个迭代器之间的元素个数 | distance(it1, it2) |
std::begin |
返回容器首元素的迭代器 | begin(container) |
std::end |
返回容器尾后位置的迭代器 | end(container) |
std::rbegin |
返回容器末元素的反向迭代器 | rbegin(container) |
std::rend |
返回容器首前位置的反向迭代器 | rend(container) |
std::inserter |
创建可在指定位置插入元素的插入迭代器 | inserter(container, position) |
std::back_inserter |
创建可在容器末尾追加元素的插入迭代器 | back_inserter(container) |
std::front_inserter |
创建可在容器开头插入元素的插入迭代器 | front_inserter(container) |
迭代器的应用及示例
在 C++ 中,迭代器在与 STL 容器和算法配合时被广泛使用。下面列出几种主要应用场景,并给出对应代码示例。
1. 遍历容器
最基本用途:利用 begin() 与 end() 获取首尾迭代器,不断自增直至两迭代器相等,即可完成整个容器的遍历。
cpp
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> s = {10, 20, 30, 40, 50};
// 获取起始迭代器
auto it = s.begin();
// 顺序遍历集合
while (it != s.end()) {
cout << *it << " "; // 通过迭代器访问元素
++it; // 移至下一元素
}
return 0;
}
10 20 30 40 50
说明:此方法适用于所有 STL 容器。
2. 反向遍历容器
借助反向迭代器,无需手动反转容器即可从尾到头遍历。
cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vec = {10, 20, 30, 40, 50};
// 反向迭代器指向末尾元素
auto it = vec.rbegin();
// 反向遍历向量
while (it != vec.rend()) {
cout << *it << " ";
++it;
}
return 0;
}
50 40 30 20 10
3. 容器无关的算法
迭代器让算法脱离具体容器类型,例如 std::sort()、std::find()、std::for_each() 等只需接收迭代器范围即可工作。
cpp
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
using namespace std;
int main()
{
vector<int> vec = {30, 10, 40, 10, 50};
multiset<int> ms = {10, 30, 10, 20, 40, 10};
// 统计 vector 与 multiset 中 10 的出现次数
cout << "10s in Vector: " << count(vec.begin(), vec.end(), 10) << endl;
cout << "10s in Multiset: " << count(ms.begin(), ms.end(), 10) << endl;
return 0;
}
yaml
10s in Vector: 2
10s in Multiset: 3