C++ 迭代器

迭代器是一种指针状对象,表示容器中某个元素的位置。它用于遍历容器中的元素。

假设我们有一个大小为4的向量(vector)名为nums。那么,begin()end()是成员函数,分别返回指向向量开头和结尾的迭代器。

  • nums.begin()指向向量中的第一个元素,即**第0**个索引
  • nums.begin() + i指向**第i**个索引处的元素。
  • nums.end()指向向量中最后一个元素之后的理论位置
begin() and end() iterators identify the beginning and the end of the container.
向量迭代器

注意: C++ STL 容器提供迭代器,以便 STL 算法可以独立于所使用的容器类型进行应用。


定义迭代器

我们可以使用以下语法定义迭代器

// create a vector iterator
vector<int>::iterator vec_itr;

// create a map iterator
map<char, int>::iterator map_itr;

在这里,我们创建了迭代器vec_itrmap_itr,以便遍历向量或映射中的元素。

请始终记住,我们不能将迭代器用于具有不匹配数据类型的容器。例如,

// create vector of integer type
vector<int> num {1, 2, 3};

// Error: itr can only be used with integer vectors
vector<double>::iterator itr = num.begin();

注意: 我们可以使用auto关键字(C++ 11 及更高版本)在初始化时推断迭代器的类型。

例如,

vector<string>::iterator itr = languages.begin();

可以写成

auto itr = languages.begin();

示例 1:C++ 迭代器

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

int main() {

    vector <string> languages = {"Python", "C++", "Java"};

// create an iterator to a string vector vector<string>::iterator itr;
// iterate over all elements for (itr = languages.begin(); itr != languages.end(); itr++) { cout << *itr << ", "; }
return 0; }

输出

Python, C++, Java,

在上面的示例中,我们使用了一个迭代器itr来遍历一个名为languages的向量。

这里,

  • itr = languages.begin() - 将指向第一个向量元素的迭代器赋值给itr
  • itr != languages.end() - 检查itr是否已到达向量末尾
  • itr++ - 将itr递增到下一个位置
  • *itr - 返回itr位置的向量元素

迭代器的基本操作

下表显示了可以对迭代器执行的一些基本操作。

操作 描述
*itr 返回当前位置的元素
itr->m 返回迭代器指向的对象的成员值m,等同于(*itr).m
++itr 将迭代器移到下一个位置
-–itr 将迭代器移到上一个位置
itr + i 将迭代器移动i个位置
itr1 == itr2 如果迭代器指向的位置相同,则返回true
itr1 != itr2 如果迭代器指向的位置不同,则返回true
itr = itr1 itr1指向的位置赋值给itr迭代器

注意: 并非所有上述操作都可用于所有类型的迭代器。在学习不同类型的迭代器后,我们将进一步讨论这一点。


迭代器类型

C++ 标准模板库提供了五种类型的迭代器。它们是

  • 输入迭代器
  • 输出迭代器
  • 前向迭代器
  • 双向迭代器
  • 随机访问迭代器
Input Iterators, Output Iterators, Forward Iterators, Bidirectional Iterators, and Random Access Iterators are the five types of C++ iterators.
C++ 迭代器类型

如上图所示,随机访问迭代器也是双向迭代器,并具有附加功能。

同样,双向迭代器也是前向迭代器,并具有附加功能,依此类推。


输入迭代器

C++ 输入迭代器能够**读取/处理**一些值,同时**向前迭代**。

我们可以使用++向前迭代,并使用*读取值或使用->访问成员值。

从输入流读取值的迭代器是输入迭代器的示例。

它可以创建为

// create an input iterator to read values from cin
istream_iterator<int> input_itr(cin);

在这里,我们创建了一个名为input_itr的整数类型输入迭代器,它从标准输入流cin读取输入值。

注意: 输入和输出迭代器是 C++ STL 迭代器的一部分,并在 <iterator> 头文件中定义。


输出迭代器

C++ 输出迭代器能够**写入**一些值,同时**向前迭代**。

我们可以使用++向前迭代,并使用*读写值。=运算符可用于写入值

将值写入输出流的迭代器是输出迭代器的示例。

// create an output iterator to write integers to the console
ostream_iterator<int> output_itr(cout, " ");

在这里,我们创建了一个名为output_itr的整数类型输出迭代器,它将值写入标准输出流cout


前向迭代器

C++ 前向迭代器能够**读取/写入**一些值,同时**向前迭代**。

forward_list类的迭代器是前向迭代器。

我们可以使用++向前迭代,并使用*读写值,或使用->读写成员值。

例如,

#include <iostream>
#include <forward_list>
using namespace std;

int main() {

    forward_list<int> nums{1, 2, 3, 4};

    // initialize an iterator to point
    // to beginning  of a forward list
    forward_list<int>::iterator itr = nums.begin();

while (itr != nums.end()) { // access iterator value using indirection operator int original_value = *itr; // assign new value using indirection operator *itr = original_value * 2; // forward the iterator to next position itr++; }
// display the contents of nums for (int num: nums) { cout << num << ", "; } return 0; }

输出

2, 4, 6, 8, 

在上面的示例中,我们创建了一个前向列表nums和一个前向迭代器itr指向前向列表的开头。

然后,我们使用itr来访问和修改nums的内容。

最后,我们使用范围 for 循环来显示修改后的前向列表的元素。


双向迭代器

C++ 双向迭代器能够向前和向后迭代。

我们可以使用++向前迭代,使用--向后迭代,并使用*读写值,或使用->读写成员值。

容器类listsetmultisetmapmultimap的迭代器是双向迭代器。

#include <iostream>
#include <list>
using namespace std;

int main() {

    list<int> nums {1, 2, 3, 4, 5};

    // initialize iterator to point to beginning of nums
    list<int>::iterator itr = nums.begin();

    cout << "Moving forward: " << endl;

// display the elements in forward order while (itr != nums.end()) { cout << *itr << ", "; // move iterator by 1 position forward itr++; }
cout << endl << "Moving backward: " << endl;
// display the elements in backward order while (itr != nums.begin()) { if (itr != nums.end()) { cout << *itr << ", "; } // move iterator by 1 position backward itr--; } cout << *itr << endl;
return 0; }

输出

Moving forward: 
1, 2, 3, 4, 5, 
Moving backward: 
5, 4, 3, 2, 1

在上面的示例中,我们创建了一个列表nums和一个双向迭代器itr指向列表的开头。

然后,我们使用itr以正向和反向顺序访问和显示nums的内容。


随机访问迭代器

C++ 随机访问迭代器除了具有双向迭代器的所有属性外,还具有随机访问能力。

随机访问迭代器的一些常用运算符是

  • ++ - 向前迭代
  • -- - 向后迭代
  • *[] - 读写值
  • -> - 访问成员值
  • + - 向前移动指定步数
  • - - 向后移动指定步数

容器类vectordequearray以及字符串的迭代器是随机访问迭代器。

这是一个例子,

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

int main() {

    // create a vector
    vector<int> vec{1, 2, 3, 4};

    // create iterators to point to the first and the last elements 
    vector<int>::iterator itr_first = vec.begin();
    vector<int>::iterator itr_last = vec.end() - 1;

// display the vector elements cout << "First Element: " << *itr_first << endl; cout << "Second Element: " << itr_first[1] << endl; cout << "Second Last Element: " << *(itr_last - 1) << endl; cout << "Last Element: " << *(itr_last) << endl;
return 0; }

输出

First Element: 1
Second Element: 2
Second Last Element: 3
Last Element: 4

在上面的示例中,我们创建了一个向量vec和两个随机访问迭代器itr_firstitr_last,分别指向向量的开头和结尾。

然后,我们使用这些迭代器以随机顺序访问vec的内容并显示它们。


迭代器支持的运算符

如前所述,并非所有运算符都与所有类型的迭代器兼容。下表显示了可用于不同迭代器的运算符。

迭代器类型 支持的运算符
输入迭代器 ++, *, ->, ==, !=
输出迭代器 ++, *, =
前向迭代器 ++, *, ->, ==, !=
双向迭代器 ++, --, *, ->, ==, !=
随机访问迭代器 ++, --, *, ->, [], +, -, <, <=, >, >=, ==, !=

为什么使用迭代器?

以下是您可能想在 C++ 中使用迭代器的一些原因

  • 支持算法: C++ 标准库提供了广泛的算法,可与迭代器一起使用,例如 std::find()std::sort()std::accumulate()。这些算法使我们能够对容器执行常见操作。
  • 内存效率: 迭代器允许我们一次处理一个元素的大型数据集,而无需一次性加载整个数据集,从而提高了内存效率。
  • 一致性: 迭代器提供了一种以一致的方式访问和操作不同类型容器数据的方法。我们可以对向量、列表、集合或任何其他容器使用相同的迭代器语法。
  • 简化代码: 迭代器可以通过隐藏遍历容器的细节来简化代码,从而使代码更具可读性。

常见问题

迭代器和指针有什么区别?

迭代器和指针类似,因为它们都访问存储在特定内存位置的值。

但它们在许多其他方面也不同,如下表所示

迭代器 指针
用于遍历向量、列表等容器。 用于指向内存位置。
当底层容器被修改时,可能会失效。 即使底层数据结构被修改,仍然有效。
可与 std::find()std::sort() 等算法一起使用。 不能与 std::find()std::sort() 等算法一起使用。
可与范围 for 循环一起使用。 不能与范围 for 循环一起使用。
可根据其功能分为输入、输出、前向、双向或随机访问迭代器。 指针本质上是随机访问的。
如何创建常量迭代器?

常量迭代器是一种指向常量值的迭代器。常量迭代器本身可以递增或递减,但它指向的元素的值不能被修改。

它可以使用容器类提供的const_iterator类型来创建。

例如,

// create a vector of int type
vector <int> vec {1, 2, 3};

// create a constant iterator pointing to the beginning of the vector
vector<int>::const_iterator itr = vec.cbegin();

请注意,使用了cbegin()而不是begin()。这是因为cbegin()返回常量迭代器,而begin()返回普通迭代器。

begin()、rbegin()、end()、rend()、cbegin() 和 cend() 有什么区别?
begin() 返回一个指向容器第一个元素的迭代器。
rbegin() 返回一个指向容器最后一个元素的反向迭代器。
cbegin() 返回一个指向容器第一个元素的常量迭代器。
end() 返回一个指向容器最后一个元素之后理论元素的迭代器。
rend() 返回一个指向容器第一个元素之前理论元素的反向迭代器。
cend() 返回一个指向容器最后一个元素之后理论元素的常量迭代器。

注意: 普通迭代器和反向迭代器不兼容。

例如,

vec.rbegin() 不等于 vec.end() - 1,即使它们指向同一个元素。

vec.rbegin() == vec.end() - 1; // not defined
*(vec.rbegin()) ==  *(vec.end() -1) // defined and true
advance()、next() 和 previous() 函数是什么?

在 C++ 中,advance()next()previous() 是迭代器函数,用于将迭代器移动到容器中的特定位置。下面对每个函数进行了简要说明

  • advance() - 将迭代器向前或向后移动指定的位数。advance()的语法如下

    std::advance(itr, n); // moves the iterator n positions forward
    std::advance(itr, -n); // moves the iterator n positions backward
  • next() - 返回一个距离当前迭代器n个位置的元素的迭代器。next()的语法如下

    std::next(itr, n); // returns an iterator n positions forward from itr
  • previous() - 返回一个距离当前迭代器n个位置之前的元素的迭代器。previous()的语法如下

    std::previous(itr, n); // returns an iterator n positions before itr
你觉得这篇文章有帮助吗?

我们的高级学习平台,凭借十多年的经验和数千条反馈创建。

以前所未有的方式学习和提高您的编程技能。

试用 Programiz PRO
  • 交互式课程
  • 证书
  • AI 帮助
  • 2000+ 挑战