目录
概述
vector是STL的容器之一。vector的底层结构类似于数组——在内存中开辟一块连续的空间。与数组不同的是vector可以动态的改变空间的大小(扩容或缩容)。
vector一般不会缩容,而是会经常的扩容——扩容的大小总比用户需要的多,这和vector的扩容机制有关。
vector不支持原地扩容,会新开辟一块更大的空间。将旧空间的值浅拷贝给新空间,然后释放旧空间。vector的空间的动态改变是有代价的,尤其是数据量特别大时,不会轻易缩容。
不同平台的扩容原则是一样的,但扩容的细节并不相同。VS下是根据旧空间的1.5倍扩容,g++是根据旧空间的2倍扩容。
迭代器
vector的迭代器不需要像list的那样把普通指针进行封装,详见:http://t.csdnimg.cn/76tVf
因为vector维护的是一段线性空间,它的底层是一块连续的空间。普通的指针刚好能完成数据的随机访问,空间的遍历,数据的存取等。下面是迭代器的源码定义。
templat <class T, class Alloc = alloc>
class vector
{
public:
typedef T value_type;
typedef value_type* iterator;
//......
}
T*就是vector的迭代器。如果vector存的是int类型的数据,vector的迭代器就是int*类型的指针。存的如果是string类(自定义类型)类型的数据,vector的迭代器就是string*类型的指针。
迭代器失效
扩容会引发迭代器失效。首先获取了一个空间的迭代器,然后这个空间发生了扩容,此时这个迭代器是指向旧空间的,旧空间会被归还给操作系统。这种情景下的迭代器失效可以理解为野指针问题。VS环境下会强制报错。如下图
数据结构
vector管理线性空间用了三个迭代器,如下是源代码定义
templat <class T, class Alloc = alloc>
class vector
{
//......
protected:
iterator start;
iterator finish;
iterator end_of_storage;
//......
}
start——指向空间的开头
finish——指向有效数据的下一个位置
end_of_storage——指向有效空间的下一个位置
优点和缺点
优点:支持随机访问,排序消耗的时间复杂度比其他容器低
有如下代码,验证三大容器vector, list, deque,在相同数据量,相同数据,数据的顺序也相同的情况下,用vector容器的排序有多大优势。在release环境下验证
#include<vector>
#include<list>
#include<deque>
#include<algorithm>
#include<time.h>
#include<iostream>
void Test()
{
//数据量
int N = 100000;//十万
//int N = 1000000;//百万
//int N = 10000000;//千万
//int N = 100000000;//一亿
std::vector<int> v; //三大容器
std::list<int> l;
std::deque<int>d;
for (int i = N; i > 0; i--) //插入相同的数据,数据顺序也相同
{
int e = rand();
v.push_back(e);
l.push_back(e);
d.push_back(e);
};
clock_t begin1 = clock(); //时间函数
sort(v.b