选用哪种容器,需要考虑的问题无非是两点:容器的特点和我们需要对数据进行如何操作。
下面先简要介绍一下vector、list和deque三种容器的特点:
vector容器相当于数组,但是不需要定义它的大小。vector有一个重要的特征,就是:它里面的数据时连续储存的!理解了这一点,就不难理解vector的两个重要的特点:支持快速的随机访问和随机插入或者删除元素时效率低下。因为是连续储存的,所以当我们想要访问其中的任意一个元素时,只需要提供这个元素与第一个元素的偏移量就可以了。为什么说插入或者删除效率低下呢?因为如果你插入(或者删除)一个元素,那么他后面的所有元素都需要重新移动自己的位置。因此,vector定义了push_back操作来支持在容器的尾部插入元素,这个操作效率比较高,因为这样做并没有移动其他的元素。但这又存在一个潜在的问题,就是vector在定义的时候,是不知道你要往它里面push_back多少个元素的,怎么给它分配合适的内存大小呢?对于每一个每一个vector,它其中有多少元素,那么它的size()操作就返回多少;但是vector还有capacity()操作,来返回这个容器的容量,就是最大能插入多少个元素。容器已经满了,即size = capacity,那么再给vector添加元素时,不得不重新开辟一段空间,并把原来的值复制过去了。
我们看一段程序:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> iVec;
for(int i = 1; i != 11; ++i)
{
iVec.push_back(i);
cout<<"size = "<<iVec.size()<<"\t"
<<"capacity = "<<iVec.capacity()<<endl;
}
//用完所有容量
while(iVec.size() != iVec.capacity())
iVec.push_back(0);
cout<<"当前容量已经用完:"<<endl;
//此时再添加一个元素
iVec.push_back(0);
cout<<"size = "<<iVec.size()<<"\t"
<<"capacity = "<<iVec.capacity()<<endl;
return 0;
}
从程序总可以看出,新的空间的大小等于原空间大小的1.5倍(19 = 13+13/2)
再看list。list相当于链表。每一个节点都有前驱指针,后继指针以及数据元素组成。它依靠指针把整个结构串联起来,不需要顺序储存。也正是因为整个原因,它的随机访问性能非常不好,要想访问某一个特定的元素,必须从头开始,沿着指针依次访问这个元素前面的每一个元素,直到找到它为止。但是使用指针意味着可以高性能的插入或者删除链表中的任意一个元素:只用改变指针的指向就可以了。
deque相当于二者的结合,使用多个连续的存储块。这意味它支持随机访问,但是效果没有vector好,也支持在内部插入或者删除元素,但性能不及list。deque支持高效地在头部插入。
通常而言,当我们需要随机访问和在尾部插入时时,考虑vector,需要随机插入或者删除时,考虑list,如果需要在两头插入或者删除,则考虑deque。