学而时习之:C++中的标准模板4

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.给迭代器加减整数

只有随机访问迭代器 (如 vectordeque 的迭代器)才支持给迭代器加上或减去一个整数,从而一次性向前或向后跳跃多个位置。
listsetmap 等容器的迭代器不支持这种算术运算。

示例代码:

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.迭代器相减

我们可以将一个迭代器减去另一个迭代器,从而得到它们之间相隔的元素个数(即距离)。

该操作同样仅适用于随机访问迭代器 (如 vectordeque)。

示例代码:

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 中的迭代器可按"允许执行的操作"进行分类:

  1. 输入迭代器(Input Iterator)

    只能顺序读取容器元素(单向一次遍历)。

    支持容器如 istream_iterator

    支持运算符:*++==!=

  2. 输出迭代器(Output Iterator)

    只能顺序写入容器元素(单向一次遍历)。

    支持容器如 ostream_iterator

    支持运算符:*++

  3. 前向迭代器(Forward Iterator)

    读写 元素,并允许多次遍历

    支持容器如 forward_listunordered_setunordered_map

    支持运算符:*++==!=

  4. 双向迭代器(Bidirectional Iterator)

    可在容器中前后双向移动

    支持容器如 listsetmapmultisetmultimap

    支持运算符:*++--==!=

  5. 随机访问迭代器(Random Access Iterator)

    可使用算术运算自由跳转到任意位置。

    支持容器如 vectordequearray

    支持运算符: *++--+-[]<><=>=

迭代器适配器

C++ 中的迭代器适配器是一种基于传统迭代器构建的特殊迭代器,用于提供专门的功能。常见的迭代器适配器如下:

迭代器适配器类型 说明
反向迭代器(Reverse Iterator) 基于双向或更高级迭代器构建,允许用户反向遍历容器。
流迭代器(Stream Iterators) 包括 istream_iteratorostream_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
相关推荐
蓑衣夜行1 小时前
Qt QWebEngine 开启硬件加速注意事项
开发语言·c++·qt·web·qwebengine
EverestVIP2 小时前
C++中的mutable关键字如何使用
c++
黑客思维者2 小时前
智能配电系统用户敏感数据脱敏详细设计:从静态遮盖到动态策略
c++·python·嵌入式系统·数据脱敏·智能配电系统
GoWjw3 小时前
内存管理【3】
linux·服务器·c++·ubuntu
liulilittle4 小时前
C++ 并发双阶段队列设计原理与实现
linux·开发语言·c++·windows·算法·线程·并发
森G4 小时前
五、Linux字符设备驱动
linux·arm开发·c++·ubuntu
繁星蓝雨4 小时前
我与C++的故事(杂谈)
开发语言·c++
Queenie_Charlie5 小时前
和为k的连续区间
数据结构·c++·map
white-persist6 小时前
【攻防世界】reverse | Mysterious 详细题解 WP
c语言·开发语言·网络·汇编·c++·python·安全