一、容器是什么
1、简单的理解容器,它就是一些模板类的集合,但和普通模板类不同的是,容器中封装的是组织数据的方法(也就是数据结构)。
2、STL 提供有 3 类标准容器,分别是序列容器、排序容器和哈希容器,其中后两类容器有时也统称为关联容器。
3、在实际使用时,要善于根据想实现的功能,选择合适的容器。
二、迭代器是什么
1、无论是序列容器还是关联容器,最常做的操作无疑是遍历容器中存储的元素,而实现此操作,多数情况会选用“迭代器(iterator)”来实现。
2、尽管不同容器的内部结构各异,但它们本质上都是用来存储大量数据的,换句话说,都是一串能存储多个数据的存储单元。因此,诸如数据的排序、查找、求和等需要对数据进行遍历的操作方法应该是类似的。
3、既然类似,完全可以利用泛型技术,将它们设计成适用所有容器的通用算法,从而将容器和算法分离开。但实现此目的需要有一个类似中介的装置,它除了要具有对容器进行遍历读写数据的能力之外,还要能对外隐藏容器的内部差异,从而以统一的界面向算法传送数据。
3、这是泛型思维发展的必然结果,于是迭代器就产生了。迭代器和C++的指针非常类似,它可以是需要的任意类型,通过迭代器可以指向容器中的某个元素,如果需要,还可以对该元素进行读/写操作。
三、迭代器类别
1、容器的迭代器的功能强弱,决定了该容器是否支持 STL 中的某种算法。常用的迭代器按功能强弱分为输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器 5 种。本节主要介绍后面的这 3 种迭代器。
2、不同的迭代器
3、C++ 11 标准中不同容器指定使用的迭代器类型。
四、迭代器的定义方式
1、通过定义以上几种迭代器,就可以读取它指向的元素,*迭代器名就表示迭代器指向的元素。其中,常量迭代器和非常量迭代器的分别在于,通过非常量迭代器还能修改其指向的元素。另外,反向迭代器和正向迭代器的区别在于:
- 对正向迭代器进行 ++ 操作时,迭代器会指向容器中的后一个元素;
- 而对反向迭代器进行 ++ 操作时,迭代器会指向容器中的前一个元素。
2、注意,以上 4 种定义迭代器的方式,并不是每个容器都适用。有一部分容器同时支持以上 4 种方式,比如 array、deque、vector;而有些容器只支持其中部分的定义方式,例如 forward_list 容器只支持定义正向迭代器,不支持定义反向迭代器。
五、举个栗子吃吃吧
以上对迭代器做了很详细的介绍,下面就以 vector 容器为例,带领大家实际感受迭代器的用法和功能。通过前面的学习,vector 支持随机访问迭代器,因此遍历 vector 容器有以下几种做法。下面的程序中,每个循环演示了一种做法:
// 便利vector容器
#include <iostream>
// 引入需要的vector头文件
#include <vector>
using namespace std;
int main() {
vector<int> v{ 1,2,3,4,5,6,7,8,9,10 }; //v被初始化成有10个元素
cout << "第一种遍历的用法" << endl;
// size返回元素个数
for (int i = 0; i < v.size();++i) {
// 像普通数组那样使用vector容器
cout << v[i] << " ";
}
// 创建一个正向迭代器,当然vector也支持其他三种迭代
cout << "第二种迭代器方法" << endl;
vector<int>::iterator i;
for (i = v.begin();i != v.end();++i) {
cout << *i << " ";
}
cout << endl << "第三种遍历方法:" << endl;
for (i = v.begin(); i < v.end(); ++i) {
cout << *i << " ";
}
cout << endl << "第四种遍历方法:" << endl;
i = v.begin();
while (i < v.end()) { //间隔一个输出
cout << *i << " ";
i += 2; // 随机访问迭代器支持 "+= 整数" 的操作
}
}