C++容器之迭代器(iterator)

1 概述

  迭代器是指任何指向元素范围(如数组或容器)中某个元素的对象,该对象能够使用一组运算符(至少使用增量(++)和取消引用(*)运算符)在该范围的元素中进行迭代。
  迭代器最明显的形式是指针:指针可以指向数组中的元素,并可以使用增量运算符(++)对它们进行迭代。但是其他类型的迭代器也是可能的。例如,每个容器类型(如列表)都有一个特定的迭代器类型,用于遍历其元素。
  请注意,虽然指针是迭代器的一种形式,但并非所有迭代器都具有相同的指针功能;根据迭代器支持的属性,它们分为五个不同的类别:

  • Input 输入迭代器是可以在顺序输入操作中使用的迭代器,其中迭代器指向的每个值只读取一次,然后迭代器递增。
  • Forward 前向迭代器作为迭代器,可用于访问范围内从开始到结束的元素序列。
  • Bidirectional 双向迭代器是一种迭代器,可用于在两个方向(朝向末尾和开头)访问范围内的元素序列。
  • Random-access 随机访问迭代器是一种迭代器,可用于访问相对于所指向元素的任意偏移位置的元素,提供与指针相同的功能。
  • Output 输出迭代器是可用于顺序输出操作的迭代器,其中迭代器指向的每个元素只写入一次值,然后迭代器递增。

在这里插入图片描述

2 分类

在这里插入图片描述

2.1 前向迭代器

  • std::forward_list
  • std::unordered_map
  • std::unordered_multimap
  • std::unordered_set
  • std::unordered_multiset

2.2 双向迭代器

  • std::list
  • std::map
  • std::multi_map
  • std::set
  • std::multi_set

2.3 随机访问迭代器

  • std::array
  • std::deque
  • std::vector

3 接口

3.1 advance

使迭代器前进n个元素位置。

void IteratorSuite::advance()
{
    std::list<int> a = { 0, 1, 2, 3, 4, 5 };
    auto it = a.begin();

    std::advance(it, 3);
    TEST_ASSERT_EQUALS(3, *it)

    std::advance(it, 1);
    TEST_ASSERT_EQUALS(4, *it)

    std::advance(it, 1);
    TEST_ASSERT_EQUALS(5, *it)

    std::advance(it, 1);
    TEST_ASSERT_EQUALS(true, it == a.end())
}

说明:

  • 如果它是一个随机访问迭代器,则函数只使用一次运算符+或运算符-。
  • 否则,函数会重复使用递增或递减运算符(运算符++或运算符-),直到n个元素被推进。
  • 参数应至少是一个输入迭代器。

3.2 distance

计算介于第一个和最后一个迭代器之间的元素数。

void IteratorSuite::distance()
{
    std::vector<int> a = { 0, 1, 2, 3, 4, 5 };
    std::forward_list<int> b = { 0, 1, 2, 3, 4, 5 };

    auto size = std::distance(a.begin(), a.end());
    TEST_ASSERT_EQUALS(6, size)

    size = std::distance(b.begin(), b.end());
    TEST_ASSERT_EQUALS(6, size)
}

说明:

  • 如果它是一个随机访问迭代器,则函数只使用一次运算符-。
  • 否则,该函数将重复使用递增运算符(运算符++)。
  • 参数应至少是一个输入迭代器。

3.3 begin

返回一个迭代器,该迭代器指向序列中的第一个元素:

void IteratorSuite::begin()
{
    int array[] = { 1, 2, 3, 4, 5, 6 };
    std::vector<int> a;
    auto begin = std::begin(array);
    auto end = std::end(array);

    a.reserve(std::distance(begin, end));
    for(auto it = begin; it != end; ++it)
        a.push_back(*it);
    
    int index = 0;
    for(auto i : a)
        TEST_ASSERT_EQUALS(array[index++], i)
}

说明:

  • 支持容器与数组
  • 如果是容器,该函数返回container.begin()
  • 如果是数组,该函数返回其参数的数组到指针的转换。

3.4 end

返回一个迭代器,该迭代器指向序列中最后一个元素后面的位置。

void IteratorSuite::end()
{
    int array[] = { 1, 2, 3, 4, 5, 6 };
    std::vector<int> a;
    auto begin = std::begin(array);
    auto end = std::end(array);

    a.reserve(std::distance(begin, end));
    for(auto it = begin; it != end; ++it)
        a.push_back(*it);
    
    int index = 0;
    for(auto i : a)
        TEST_ASSERT_EQUALS(array[index++], i)
}
  • 支持容器与数组
  • 如果是容器,该函数返回container.end()
  • 如果是数组,该函数返回array + N。

3.5 prev

返回一个迭代器,该迭代器指向在advance(-n)位置时它将指向的元素。

void IteratorSuite::prev()
{
    std::list<int> a = { 0, 1, 2, 3, 4, 5 };
    auto it = std::prev(a.end());
    TEST_ASSERT_EQUALS(5, *it)

    it = std::prev(it, 2);
    TEST_ASSERT_EQUALS(3, *it)
}

说明:

  • 如果它是一个随机访问迭代器,则函数只使用一次运算符+或运算符-。
  • 否则,该函数会在复制的迭代器上重复使用递增或递减运算符(运算符++或运算符–),直到n个元素被推进。
  • 参数应至少是一个双向迭代器。

3.6 next

返回一个迭代器,该迭代器指向在advance(n)位置时要指向的元素。

void IteratorSuite::next()
{
    std::list<int> a = { 0, 1, 2, 3, 4, 5 };
    auto it = std::next(a.begin(), 3);
    TEST_ASSERT_EQUALS(3, *it)

    it = std::next(it);
    TEST_ASSERT_EQUALS(4, *it)

    it = std::next(it);
    TEST_ASSERT_EQUALS(5, *it)

    it = std::next(it);
    TEST_ASSERT_EQUALS(true, it == a.end())
}
  • 如果它是一个随机访问迭代器,则函数只使用一次运算符+或运算符-。
  • 否则,该函数会在复制的迭代器上重复使用递增或递减运算符(运算符++或运算符–),直到n个元素被推进。
  • 参数应至少是一个前向迭代器。

3.7 back_inserter

构造一个后插入迭代器,在x的末尾插入新元素。

void IteratorSuite::back_inserter()
{
    int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    std::list<int> a = { 1, 2, 3, 4, 5 };
    std::list<int> b = { 6, 7, 8, 9, 10 };

    std::copy(b.begin(), b.end(), std::back_inserter(a));
    int index = 0;
    for(auto it = a.begin(); it != a.end(); ++it)
        TEST_ASSERT_EQUALS(array[index++], *it)
}

说明:

  • 容器需要有push_back接口

3.8 front_inserter

构造一个前插入迭代器,在x的开头插入新元素。

void IteratorSuite::front_inserter()
{
    int array[] = { 5, 4, 3, 2, 1, 6, 7, 8, 9, 10 };
    std::list<int> a = { 1, 2, 3, 4, 5 };
    std::list<int> b = { 6, 7, 8, 9, 10 };
    std::copy(a.begin(), a.end(), std::front_inserter(b));

    int index = 0;
    for(auto it = b.begin(); it != b.end(); ++it)
        TEST_ASSERT_EQUALS(array[index++], *it)
}

说明:

  • 容器需要有push_front接口

3.9 inserter

构造一个插入迭代器,从x指向的位置开始,在连续的位置将新元素插入到x中。

void IteratorSuite::inserter()
{
    int array[] = { 6, 7, 8, 1, 2, 3, 4, 5, 9, 10 };
    std::list<int> a = { 1, 2, 3, 4, 5 };
    std::list<int> b = { 6, 7, 8, 9, 10 };

    auto it = std::next(b.begin(), 3);
    std::copy(a.begin(), a.end(), std::inserter(b, it));

    int index = 0;
    TEST_ASSERT_EQUALS(5, a.size())
    for(auto it = b.begin(); it != b.end(); ++it)
        TEST_ASSERT_EQUALS(array[index++], *it)
}

说明:

  • 容器需要有insert接口

3.10 make_move_iterator

move_iterator是一个迭代器适配器,它对迭代器(it)进行适配,以便取消对它的引用产生右值引用(就像应用了std::move一样),而所有其他操作的行为都相同。

void IteratorSuite::make_move_iterator()
{
    std::string array[] = { "a", "b", "c" };
    std::list<std::string> a(3);
    std::list<std::string> b{"a", "b", "c"};
    std::copy(std::make_move_iterator(b.begin()),
        std::make_move_iterator(b.end()), a.begin());
    
    TEST_ASSERT_EQUALS(3, b.size())
    TEST_ASSERT_EQUALS(3, a.size())

    int index = 0;
    for(auto s : a)
        TEST_ASSERT_EQUALS(array[index++], s)
    for(auto s : b)
        TEST_ASSERT_EQUALS(true, s.empty())
}

说明:

  • 调用make_move_iterator后迭代器变为move_iterator类型,赋值操作变成移动赋值操作。
  • 如上容器b中元素变成空元素
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

flysnow010

你的鼓励就是我最大的创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值