C++ 迭代器
迭代器就像指针一样用于访问容器中的元素。
重点
- 迭代器用于遍历从一个元素到另一个元素,这个过程称为 通过容器迭代 。
- 迭代器的主要优点是为所有容器类型提供一个公共接口。
- 迭代器使算法与使用的容器类型无关。
- 迭代器提供了一种通用的方法来遍历容器的元素。
语法
<ContainerType> :: iterator;
<ContainerType> :: const_iterator;
迭代器上的操作
- 操作符 (
*
) : “*
” 操作符返回迭代器当前指向的位置的元素。 - 操作符 (
++
) : “++
” 操作符将迭代器增加1。因此,迭代器指向容器的下一个元素。 - 操作符 (
==
) 和操作符 (!=
) : 这些操作符确定两个迭代器是否指向相同的位置。 - 操作符 (
=
) : “=
” 操作符用于赋值迭代器。
迭代器与指针的区别
迭代器可以是智能指针,可以遍历复杂的数据结构。容器提供其迭代器类型。因此,我们可以说迭代器具有不同容器类型的共同接口。
容器类提供了两个基本成员函数,允许遍历或移动容器的元素:
- begin() :begin() 函数返回指向容器第一个元素的迭代器。
- end() :end() 函数返回指向容器末尾元素的迭代器。
让我们看一个简单的示例:
#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
迭代器类别
以下是迭代器的分类方式:
- 输入迭代器
- 输出迭代器
- 前向迭代器
- 双向迭代器
- 随机访问迭代器
输入迭代器: 输入迭代器是用来访问容器元素的迭代器,但不修改容器的值。
输入迭代器使用的运算符有:
- 递增运算符(
++
) - 等于运算符(
==
) - 不等于运算符(
!=
) - 解引用运算符(
*
)
输出迭代器: 输出迭代器是用来修改容器的值的迭代器,但不从容器中读取值。因此,我们可以说输出迭代器是“只写”迭代器。
输出迭代器使用的运算符有:
- 递增运算符(
++
) - 赋值运算符(
=
)
正向迭代器: 正向迭代器是用来读写容器的迭代器。它是一个多通道迭代器。
正向迭代器使用的运算符有:
- 递增运算符(
++
) - 赋值运算符(
=
) - 等于运算符(
==
) - 不等于运算符(
!=
)
双向迭代器: 双向迭代器支持正向迭代器的所有功能,还添加了一个功能,即递减运算符(–)。我们可以通过递减迭代器向后移动。
双向迭代器使用的运算符有:
- 递增运算符(
++
) - 赋值运算符(
=
) - 等于运算符(
==
) - 不等于运算符(
!=
) - 递减运算符(
--
)
随机访问迭代器: 随机访问迭代器提供对任意位置元素的随机访问。它具有双向迭代器的所有功能,还添加了一个功能,即指针加法和指针减法,以提供对元素的随机访问。
迭代器的提供者
迭代器类别 | 提供者 |
---|---|
输入迭代器 | istream |
输出迭代器 | ostream |
前向迭代器 | |
双向迭代器 | List, set, multiset, map, multimap |
随机访问迭代器 | Vector, deque, array |
迭代器及其特点
Iterator | Access method | Direction of movement | I/O capability |
---|---|---|---|
Input | Linear | Forward only | Read-only |
Output | Linear | Forward only | Write-only |
Forward | Linear | Forward only | Read/Write |
Bidirectional | Linear | Forward & backward | Read/Write |
Random | Random | Forward & backward | Read/Write |
迭代器的缺点
- 如果我们想同时从一个数据结构移动到另一个数据结构,迭代器无法实现。
- 如果我们要更新正在迭代的数据结构,迭代器将不允许我们这样做,因为它存储位置的方式不允许。
- 如果我们在遍历一个列表时想要回溯,迭代器在这种情况下将无法工作。
迭代器的优点
以下是迭代器的优点:
- 编程简便: 使用迭代器比使用下标运算符[]方便访问容器的元素。如果我们使用下标运算符[]访问元素,则需要在运行时跟踪添加的元素数量,但在使用迭代器的情况下不需要这样做。
让我们看一个简单的示例:
#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++) // Traversal without using an iterator.
{
cout<<v[i]<<" ";
}
cout<<'\n';
for(itr=v.begin();itr!=v.end();itr++) // Traversal by using an iterator.
{
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
在上面的示例中,我们观察到,如果我们在遍历一个向量的元素时不使用迭代器,那么我们需要跟踪在容器中添加的元素的数量。
- 代码可重用性: 如果我们使用迭代器,代码可以被重用。在上面的示例中,如果我们将向量替换为列表,那么下标操作符[]无法用于访问元素,因为列表不支持随机访问。然而,如果我们使用迭代器来访问元素,那么我们可以访问列表元素。
- 动态处理: 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’步 。