一、什么是迭代器
为了提高C++编程的效率,STL(Standard Template Library)中提供了许多容器,包括vector、list、map、set等。然而有些容器(vector)可以通过下标索引的方式访问容器里面的数据,但是大部分的容器(list、map、set)不能使用这种方式访问容器中的元素。为了统一访问不同容器时的访问方式,STL为每种容器在实现的时候设计了一个内嵌的iterator类,不同的容器有自己专属的迭代器(专属迭代器负责实现对应容器访问元素的具体细节),使用迭代器来访问容器中的数据。除此之外,通过迭代器可以将容器和通用算法结合在一起,只要给予算法不同的迭代器,就可以对不同容器执行相同的操作,例如find查找函数(因为迭代器提供了统一的访问方式,这是使用迭代器带来的好处)。迭代器对一些基本操作如*、->、++、==、!=、=进行了重载,使其具有了遍历复杂数据结构的能力,其遍历机制取决于所遍历的容器,所有迭代器的使用和指针的使用非常相似。通过begin,end函数获取容器的头部和尾部迭代器,end迭代器不包含在容器之内,当begin和end返回的迭代器相同时表示容器为空。
STL主要由 容器、迭代器、算法、函数对象、和内存分配器 五大部分构成。
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v;
//初始化容器
for (int i = 0; i < 10; ++i)
{
v.push_back(i);
}
//利用迭代器遍历容器
for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{
cout << *it << " ";
}
}
二、迭代器类型
按照迭代器的功能强弱,可以把迭代器分为以下几种类型:
1、输入迭代器
功能:
- 通用的四种功能
- 只能利用迭代器进行输入功能
- 它只能用于单遍扫描算法
2、输出迭代器
功能:
- 通用的四种功能
- 只能利用迭代器进行输入功能
- 只能用于单遍扫描算法
3、前向迭代器
功能:
- 通用的四种功能
- 能利用迭代器进行输入和输出功能
- 能用于多遍扫描算法
4、双向迭代器
功能:
- 通用的四种功能
- 能利用迭代器进行输入和输出功能
- 能用于多遍扫描算法
- 前置和后置递减运算(- -),这意味这它能够双向访问
随机访问迭代器
功能:
- 通用的四种功能
- 能利用迭代器进行输入和输出功能
- 前置和后置递减运算(- -)(意味着它是双向移动的)
- 比较两个迭代器相对位置的关系运算符(<、<=、>、>=)
- 支持和一个整数值的加减运算(+、+=、-、-=)
- 两个迭代器上的减法运算符(-),得到两个迭代器的距离
- 支持下标运算符(iter[n]),访问距离起始迭代器n个距离的迭代器指向的元素
- 能用于多遍扫描算法。 在支持双向移动的基础上,支持前后位置的比较、随机存取、直接移动n个距离
三、常用容器的迭代器
vector ——随机访问迭代器
deque——随机访问迭代器
list —— 双向迭代器
set / multiset——双向迭代器
map / multimap——双向迭代器
stack——不支持迭代器
queue——不支持迭代器
四、实例
双向迭代器和随机访问迭代器是最为常用的,因此下面演示这两种迭代器的用法
双向迭代器
#include <iostream>
#include <list>
using namespace std;
int main()
{
list<int> lst;
for (int i = 0; i < 10; ++i)
{
lst.push_back(i);
}
list<int>::iterator it;//创建list的迭代器
cout << "遍历lst并打印: ";
for (it = lst.begin(); it != lst.end(); ++it)//用 != 比较两个迭代器
{
cout << *it << " ";
}
//此时it=lst.end(),这个位置是最后一个元素的下一个位置,没有存储数据
--it;//等价于it--,回到上一个位置
//it -= 1; //报错,虽然都是-1,但这种方式是随机迭代器才有的功能
cout << "\nlst的最后一个元素为:" << *it << endl;
}
随机访问迭代器
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v;
for (int i = 0; i < 10; ++i)
{
v.push_back(i);
}
vector<int>::iterator it;
for (it = v.begin(); it != v.end(); ++it) //用 != 比较两个迭代器
{
cout << *it << " ";
}
cout << endl;
for (it = v.begin(); it < v.end(); ++it) //用 < 比较两个迭代器
{
cout << *it << " ";
}
cout << endl;
it = v.begin();//让迭代器重新指向首个元素的位置
while (it < v.end())//间隔一个输出
{
cout << *it << " ";
it += 2; // 用 += 移动迭代器
}
cout << endl;
it = v.begin();
cout << it[5] << endl; //用[]访问
}
对于vector容器来说,其迭代器有失效的可能。
vector容器有动态扩容的功能,每当容器容量不足时,vector就会进行动态扩容,动态扩容不是在原来的空间后面追加空间,而是在寻找一段新的更大的空间,把原来的元素复制过去。
但是这样一来,容器存储元素的位置就改变了,原来的迭代器还是指向原来的位置,因此每次进行动态扩容后原来的迭代器就会失效。
这里可以查看之前发过的vector和list的区别。