目录
vector的介绍(翻译自C++官网)
1. vector是表示可变大小数组的序列容器
2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理
3. 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小
4. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
5. 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
6. 与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list统一的迭代器和引用更好
vector的使用
构造
vector() -- 无参构造
vector(size_type n, const value_type& val = value_type()) -- 构造并初始化n个val
vector(const vector& x); -- 拷贝构造
vector (InputIterator fifirst, InputIterator last); -- 使用迭代器进行初始化构造
定义
vector<int> ():创建一个空vector
vector<int> (int nSize):创建一个vector,元素个数为nSize
vector<int> (int nSize,const int& t):创建一个vector,元素个数为nSize,且值均为t
vector<int> v(10,1);
vector<int> (const vector<int>&):复制构造函数
vector<int> v2(v);
vector<int> (begin,end):复制 [begin,end)区间内另一个数组的元素到vector中
vector<int> vector(v1.begin(),v1.end()); -- 用v1的迭代器构造
string s("hellow world");
vector<char> vector(s.begin(),s.end()); -- 用可赋值的同类型的迭代器构造
vector<int> vector(s.begin()+3,s.end()-2);
空间问题
数据个数、容量、判空
vector<int> v();
v.size();
v.capacity();
v.empty();
开空间+初始化
vector<int> v1(10,0); //初始化为10个0
vector<int> v2;
v2.resize(10,0);
增删查改
push_back和pop_back
vector<int> v{1,2,3,4,5,6,7,8,9};
v.push_back(90);
v.pop_back();
insert和erase
iterator insert (iterator position, const value_type& val); -- 在pos位置的前面插入val
iterator erase (iterator position); -- 删除pos位置的元素 iterator erase (iterator first, iterator last); -- 删除 [first,last) 区间内的所有元素
对vector中的元素进行insert和erase时会消耗当前迭代器,同时会返回一个迭代器,所以需要重新对返回的迭代器进行获取
int arr[]={1,2,3,4,5,6,7,8,9};
int n = sizeof(arr) / sizeof(arr[0]);
vector<int> v(arr,arr+n); //用指针区间来构造
vector<int>::iterator it = v.begin();
//insert
while(it != v.end()){
if (*it == 2) {
//在2的前面插入20
it = v.insert(it, 20);
}
cout << *it << " " << endl;
it++;
}
//erase
it = v.begin(); //重置迭代器
while(it != v.end()){
if (*it == 20) {
//在2的前面插入20
it = v.erase(it);
}else{
cout << *it << " " << endl;
it++;
}
}
关于返回值:insert返回的是当前插入元素的位置,插入了20,那insert的返回值就是20的位置,但erase返回的是删除元素的下一个位置,删除了20,那erase返回的就是20的下一个元素2的位置。可以理解为返回的逻辑位置都是当前的位置,而erase删除了20,所以20已经不见了,后面的元素自动补位上来,那么原来20的位置变成2了
还有两个注意事项:
1、insert可能出现野指针 -- 返回原来插入的位置,如果有扩容行为把空间移动到别的地方了,那么原来的位置就是野指针
2、 erase可能越界 -- 删完之后指向原来的下标,后面元素补到删除元素的位置,如果所删除的是末尾元素则会越界
find
vertor没有内置find,可以用find()+迭代器来实现
//用迭代器在v对象中找2的位置
vertor<int>::iterator pos = find(v.begin(),v.end(),2);
迭代器找到的位置只能使用一次,使用完之后就会失效
结合前面的insert和erase可以这样使用
vector<int>::iterator pos = find(v.begin(), v.end(), 3);
//删除pos位置的数据,导致pos迭代器失效。
v.erase(pos);
cout << *pos << endl; //此处会导致非法访问
swap
vector<int> v1{ 1,2,3,4,5,6,7,8,9 };
vector<int> v2{ 11,12,13,14,15,16,17,18,19 };
v1.swap(v2);
//也可用swap函数直接交换
swap(v1.v2);
operator[]
和数组一样使用
用vector实现二维数组
int numRows=10;
vertor<vector<int>> vv;
resize(numRows,vector<int>()); //初始化10个vector<int>类型的元素
此时vv的使用方法就和二维数组一样了