0.顺序容器与迭代器的概念
容器:一个容器实际上就是一组相同数据类型元素的集合。相当于是对C语言中的内置数组的一种泛化。顺序容器为程序员提供了控制元素存储和访问顺序的能力。
迭代器:迭代器是C++为了更好的切合容器的使用而引入的一种特殊的数据类型。迭代器在功能上和C语言的指针十分相像,可以快速方便的访问、查找、修改容器里边的元素。
1.常用顺序容器及其迭代器
容器类型 | 数据结构 | 支持的操作 |
---|---|---|
vector | 可变长数组 | 快速随机访问 在尾部插入删除元素很快 |
deque | 双端队列 | 快速随机访问 在头、尾插入删除元素很快 |
list | 双向链表 | 双向顺序访问 任意位置插入删除元素都很快 |
forward_list | 单向链表 | 单向顺序访问 任意位置插入删除元素都快 |
array | 固定大小数组 | 快速随机访问 不能添加或者删除元素 |
string | 可变长字符数组 | 快速随机访问 尾部插入删除元素很快 |
根据上表可以得出一些结论:
除固定大小的array外,其他容器都可以添加删除元素,也就是说提供了高效、灵活的内存管理。
string和vector将元素存储在连续的内存空间,可以快速访问数据,但是删除与插入时会移动很多元素所以会很慢。
list和forward_list这两个容器的设计目的是令容器在任意位置插入和删除元素都很快,作为代价,在这两种容器中查找元素比较慢。
deque更为复杂。它支持如同string和vector的快速随机访问,在中间位置删除添加元素花费很高,但是在deque的头尾插入元素是很快的,几乎和list和forward_list花费相当。
一般来说,我们都选用vector作为常用容器,除非有更好的理由更换。
下面简单的介绍一下如何定义一个容器。
既然是容器,那么肯定能容纳不同的数据元素。我们希望vector既可以容纳int也能容纳double,而且这应当是两种不同的容器类型才可以。所以C++将所有容器都设定为模板类,通过下列方式定义容器:
vector<typename> vec;
这条语句的意思是:vec是一种vector的容器,其中容纳的元素类型是typename的
举个例子:
vector<int> intVec;
vector<double> doubleVec;
实际上,typename不必须是系统内置的类型,可以是用户自定义的类、结构体、范型
vector<myClass> vec;
vector< vector<int> > intVec;
该例子中的第二个,表示intVec是一个vector容器,容器中容纳的元素是一个int的vector(这里相当于是二维数组)
下面简单说一下迭代器。
因为迭代器可以对容器的元素访问,所以迭代器的类型必须与容器类型相匹配。
所以,迭代器的定义应该按照下述方式:
vector<int>::iterator it1;
vector<double>::iterator it2;
it1只能指向int型vector,it2只能指向double型vector。
通常,我们都是用一对迭代器来指示某一个范围。
两个迭代器分别指向同一个容器中当前元素或者是尾元素的下一个位置。
可以形象的表示为:
[begin,end)(值得一提的是,begin和end可以指向同一个元素)
表示范围从begin开始到end之前结束。
于是,给出定义,当且仅当两个迭代器begin和end满足下列所有条件时,我们称begin和end为一个迭代器对。
它们指向同一个容器的元素,或者是容器最后一个元素之后的位置
我们可以通过反复递增begin到达end,即end不在begin之前。
在这两个条件的约束下,我们可以利用迭代器循环处理一个范围内的元素
while(begin != end){
//注意这里不可以写"<"或者">",指针迭代器不可以比较大小
*begin = val;//正确,范围非空,begin指向一个元素
//迭代器是一种特殊类型的指针,因此可以通过解引用符*来访问迭代器指向内存中的数据
++begin;
}
对于标准容器,可以直接使用成员函数begin和end获得容器的迭代器。
例如: