C++教程-C++迭代器
C++ 迭代器
迭代器类似于指针,用于访问容器中的元素。
重要要点:
- 迭代器用于遍历容器中的元素,这个过程称为通过容器进行迭代。
- 迭代器的主要优点是为所有容器类型提供一个通用接口。
- 迭代器使得算法与所使用的容器类型无关。
- 迭代器提供了一种通用的方式来遍历容器的元素。
语法
<ContainerType> :: iterator;
<ContainerType> :: const_iterator;
在迭代器上执行的操作:
- 运算符(*): '*'运算符返回迭代器指向的当前位置的元素。
- 运算符(++): '++'运算符将迭代器增加一个位置。因此,迭代器指向容器的下一个元素。
- 运算符(==)和运算符(!=): 这两个运算符用于确定两个迭代器是否指向相同的位置。
- 运算符(=): '='运算符用于赋值迭代器。
迭代器与指针之间的区别
迭代器可以是智能指针,允许在复杂数据结构上进行迭代。容器提供其迭代器类型。因此,我们可以说迭代器具有不同容器类型的公共接口。
容器类提供两个基本成员函数,允许在容器的元素之间进行迭代或移动:
- 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 |
Iterators和它们的特性
迭代器 | 访问方式 | 移动方向 | 读写能力 |
---|---|---|---|
Input | 线性 | 仅向前 | 只读 |
Output | 线性 | 仅向前 | 只写 |
Forward | 线性 | 仅向前 | 读/写 |
Bidirectional | 线性 | 前后都可 | 读/写 |
Random | 随机 | 前后都可 | 读/写 |
迭代器的缺点:
- 如果我们要同时在两个数据结构之间移动,迭代器不能工作。
- 如果我们要在迭代的过程中更新结构,迭代器也不能允许我们这样做,因为它存储了位置信息。
- 如果我们在处理列表时需要回溯,迭代器在这种情况下也无法工作。
迭代器的优点:
- 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的元素,我们需要在运行时跟踪添加的元素数量。
- Code Reusability: 使用迭代器可以重用代码。在上面的例子中,如果我们将vector替换为list,那么下标操作符[]将无法用于访问元素,因为list不支持随机访问。然而,使用迭代器则可以访问list的元素。
- 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'步。这意味着随机访问迭代器在访问元素时速度更快,效率更高。