一、vector概述
vector是线性容器,元素按照线性顺序排序,容器中元素存储在一块连续的内存中,类似与数组,不过vector可以自动增长或缩小存储空间。
与数组相比:在自动处理容量的大小时会消耗更多的内存,当时vector可以提供和数组一样的性能,并且可以很好的调整存储空间的大小。
和其他标准的顺序容器相比:vector可以更有效的访问容器内元素,和在末尾添加、删除元素;而在其他位置的添加删除元素,vector不如其他顺序容器。
注意:size()返回容器的大小,大小指的是当前容器中元素的个数,cacapacity()返回的是容器的容量,容量指的是已经分配的内存的大小。
二、vector的使用
1、初始化和遍历
//三种遍历方式
//1、下标
for(int i=0; i<vec.size(); i++){
cout << vec[i] << ", ";
}
cout << endl << "---------" << endl;
//2、迭代器
for(vector<int>::iterator it = vec.begin(); it != vec.end(); it++){
cout << *it << ", ";
}
cout << endl << "---------" << endl;
//3、for each
for(int temp : vec){
cout << temp << ", ";
}
其中,vec.begin()指的是vec中第一个元素的迭代器,vec.end()指的是最后一个元素的下一个位置。
2、vector的排序
两种方式:1)如果存放的是自定义对象,则可以在类中实现<运算符,然后使用sort函数进行比较;2)自定义比较函数,在使用sort函数的时候,将比较函数当作参数传入其中。其中,sort函数是算法中的函数,头文件是algorithm。
3、查找
可以使用算法中的find函数,头文件是algorithm。如果存在则返回迭代器,否则返回vector.end()。
4、删除
三种方式:1)pop_back(),删除最后一个元素;2)erase()删除指定元素;3)clear(),删除所有元素,清空。
erase()有两种形式:
- iterator erase(iterator position)
- iterator erase(iterator first, iterator last)
使用erase的时候要注意迭代器失效的问题。
for(auto it = vec.begin(); it != vec.end(); it++){
if(*it == 3){
vec.erase(it);
}
}
此代码是错误的,当删除it的时候,it就变成了野指针,无法进行++操作的。
for(auto it = vec.begin(); it != vec.end(); it++){
if(*it == 3){
it = vec.erase(it);
}
}
此代码也是错误的:1)无法删除连续的3;2)当3位于vector的末尾,删除的时候也会出错(在vec.end()上执行了++操作)。
for(auto it = vec.begin(); it != vec.end(); ){
if(*it == 3){
it = vec.erase(it);
}else{
++it;
}
}
这才是正确的删除方式。
5、添加
有两种方式:1)insert,是在指定位置添加元素;2)push_back,是在最后添加元素
insert有三种形式:
- iterator insert(iterator pos, const TYPE &val)//在pos前插入val,返回这个元素的迭代器
- void insert(iterator pos, size_type num, const TYPE &val)//在pos前插入num个val元素
- void insert(iterator pos, input_iterator start, input_iterator end)//在pos前,插入[start, end)区间中的元素
三、小技巧
1、使用reserve ()函数提前设定容量大小
vector支持随机访问,为了提高效率,采用动态数组实现。在通过reserve函数来申请特定大小的内存空间的时候,总是按照指数边界来增大其内部缓冲区的。当进行insert或者push_back操作时,如果空间不够用,则会重新分配当前大小的1.5~2倍的新内存区,然后再把原来的内容复制过去。所以,当重新分配的操作发生时,其性能才会下降。
所以,如果有大量的数据进行添加的时候,应当使用reserve()函数提前设定其容量大小,否则会出现多次容量扩大的操作,导致效率低下。
比如,如果要存储1000个数据,可以这样做:
vector<int> vec;
vec.reserve(1000);
for(int i = 0; i < 1000; i++)
vec.push_back(i)
2、使用“交换”来调整vector过剩空间
有一种方法来把它从曾经最大的容量减少到它现在需要的容量,这样的方法常常被称之为“收缩到合适”(shrink to fit)。
该方法只需要一条语句:vector<int>(ivec).swap(ivec)。
vector<int>(ivec)表示建立一个临时的vector,它是ivec的一份拷贝。但是vector的拷贝构造函数只分配拷贝元素所需要的内存,也就是说这个临时的vector没有多余的空间。然后临时的vector和ivec进行交换数据,但是ivec只有临时变量的修正过的容量,而这个临时变量则持有了ivec曾经没有用到的容量。在这条语句的结尾处,临时vector被销毁,释放之前ivec使用的内存,而相应的ivec收缩到合适大小。