C++ 迭代器

迭代器类似于指针,用于访问容器中的元素。

重要要点:

  • 迭代器用于遍历容器中的元素,这个过程称为通过容器进行迭代
  • 迭代器的主要优点是为所有容器类型提供一个通用接口。
  • 迭代器使得算法与所使用的容器类型无关
  • 迭代器提供了一种通用的方式来遍历容器的元素。

语法

<ContainerType> :: iterator;
<ContainerType> :: const_iterator;

在迭代器上执行的操作:

  • 运算符(*): '*'运算符返回迭代器指向的当前位置的元素。
  • 运算符(++): '++'运算符将迭代器增加一个位置。因此,迭代器指向容器的下一个元素。
  • 运算符(==)和运算符(!=): 这两个运算符用于确定两个迭代器是否指向相同的位置。
  • 运算符(=): '='运算符用于赋值迭代器。

迭代器与指针之间的区别

迭代器可以是智能指针,允许在复杂数据结构上进行迭代。容器提供其迭代器类型。因此,我们可以说迭代器具有不同容器类型的公共接口。

容器类提供两个基本成员函数,允许在容器的元素之间进行迭代或移动:

  • begin(): begin()函数返回一个指向容器第一个元素的迭代器。
  • end(): end()函数返回一个指向容器最后一个元素的下一个位置的迭代器。

1.png

让我们看一个简单的例子:

#include <iostream> 
#include <iterator> 
#include <vector> 
using namespace std; 

int main() 
{ 
  std::vector<int> v{1, 2, 3, 4, 5}; 
  vector<int>::iterator itr; 
  for (itr = v.begin(); itr != v.end(); itr++) 
  { 
    std::cout << *itr << " "; 
  } 
  return 0; 
}

输出:

1 2 3 4 5

迭代器类别

迭代器可以分为以下几种类型:

  • 输入迭代器
  • 输出迭代器
  • 前向迭代器
  • 双向迭代器
  • 随机访问迭代器

2.png

输入迭代器: 输入迭代器用于访问容器中的元素,但它不会修改容器的值。

用于输入迭代器的运算符:

  • 递增运算符(++)
  • 等号运算符(==)
  • 不等号运算符(!=)
  • 解引用运算符(*)

输出迭代器: 输出迭代器用于修改容器的值,但不会从容器中读取值。因此,我们可以说输出迭代器是只写迭代器

用于输出迭代器的运算符:

  • 递增运算符(++)
  • 赋值运算符(=)

前向迭代器: 前向迭代器用于读取和写入容器。它是多通道迭代器。

用于前向迭代器的运算符:

  • 递增运算符(++)
  • 赋值运算符(=)
  • 等号运算符(=)
  • 不等号运算符(!=)

双向迭代器: 双向迭代器支持所有前向迭代器的特性,另外还增加了一个特性,即递减运算符(--)。我们可以通过递减迭代器向后移动。

用于双向迭代器的运算符:

  • 递增运算符(++)
  • 赋值运算符(=)
  • 等号运算符(=)
  • 不等号运算符(!=)
  • 递减运算符(--)

随机访问迭代器: 随机访问迭代器提供对任意位置的元素进行随机访问的能力。它具有所有双向迭代器的特性,另外还增加了指针加法和指针减法的特性,以提供对元素的随机访问。

迭代器提供者

迭代器类别提供者
输入迭代器istream
输出迭代器ostream
前向迭代器
双向迭代器List, set, multiset, map, multimap
随机访问迭代器Vector, deque, array

Iterators和它们的特性

迭代器访问方式移动方向读写能力
Input线性仅向前只读
Output线性仅向前只写
Forward线性仅向前读/写
Bidirectional线性前后都可读/写
Random随机前后都可读/写

迭代器的缺点:

  1. 如果我们要同时在两个数据结构之间移动,迭代器不能工作。
  2. 如果我们要在迭代的过程中更新结构,迭代器也不能允许我们这样做,因为它存储了位置信息。
  3. 如果我们在处理列表时需要回溯,迭代器在这种情况下也无法工作。

迭代器的优点:

  1. Ease in programming: 使用迭代器比使用下标操作符[]访问容器的元素更加方便。如果我们使用下标操作符[]来访问元素,则需要在运行时跟踪添加的元素数量,但使用迭代器则不需要。

让我们看一个简单的例子:

#include <iostream>
#include <vector>
#include <iterator>
using namespace std;

int main()
{
    vector<int> v{1, 2, 3, 4, 5};
    vector<int>::iterator itr;

    // 不使用迭代器遍历
    for (int i = 0; i < 5; i++)
    {
        cout << v[i] << " ";
    }
    cout << '\n';

    // 使用迭代器遍历
    for (itr = v.begin(); itr != v.end(); itr++)
    {
        cout << *itr << " ";
    }

    v.push_back(10);

    cout << '\n';

    // 不使用迭代器遍历(容器大小增加后,使用下标操作可能会出错)
    for (int i = 0; i < 6; i++)
    {
        cout << v[i] << " ";
    }

    cout << '\n';

    // 使用迭代器遍历(容器大小增加后,迭代器仍有效)
    for (itr = v.begin(); itr != v.end(); itr++)
    {
        cout << *itr << " ";
    }

    return 0;
}

输出:

1 2 3 4 5
1 2 3 4 5
1 2 3 4 5 10
1 2 3 4 5 10

在上面的例子中,我们可以观察到,如果我们在不使用迭代器的情况下遍历vector的元素,我们需要在运行时跟踪添加的元素数量。

  1. Code Reusability: 使用迭代器可以重用代码。在上面的例子中,如果我们将vector替换为list,那么下标操作符[]将无法用于访问元素,因为list不支持随机访问。然而,使用迭代器则可以访问list的元素。
  2. Dynamic Processing: C++迭代器提供了动态添加或删除数据的功能。

让我们看一个简单的例子:

#include <iostream>
#include <vector>
#include <iterator>
using namespace std;

int main()
{
    vector<int> v{1, 2, 3, 4, 5}; // vector declaration
    vector<int>::iterator itr;

    v.insert(v.begin() + 1, 10);

    for (itr = v.begin(); itr != v.end(); itr++)
    {
        cout << *itr << " ";
    }

    return 0;
}

输出:

1 10 2 3 4 5

在上面的例子中,我们使用insert()函数在第二个位置插入一个新元素,并使其他元素依次向后移动。

随机访问迭代器和其他迭代器之间的区别

随机访问迭代器和其他迭代器之间最重要的区别在于,随机访问迭代器只需'1'步就可以访问一个元素,而其他迭代器需要'n'步。这意味着随机访问迭代器在访问元素时速度更快,效率更高。

3.png

标签: C++语言, C++语言教程, C++语言技术, C++语言学习, C++语言学习教程, C++语言下载, C++语言开发, C++语言入门教程, C++语言进阶教程, C++语言高级教程, C++语言面试题, C++语言笔试题, C++语言编程思想