一.vector使用构造函数的四种初始化方式
//1.默认构造函数,长度为0的空向量
//vector<int> v1;
//2.带有单个整形参数的构造函数,长度为50的空向量
//vector<int> v2(50);
//vector<int> v3(50,1);//长度为50,初始值为1的向量
//3.复制构造函数,构造一个新的向量v4,作为已存在的向量v2的完全复制
//vector<int> v4(v2);
//4.带两个常量参数的构造函数,产生初始值为一个区间的向量。区间由一个左闭右开的半开区间[first,last) 来指定
//vector<int> v5(first_Iter,end_Iter);
假设有int数组: int v1[10] = {0,1,0,0,3,0,0,4,4,4};
第一种初始化方式: 带有单个整形参数的构造函数
vector<int> vecInit1(10);//和vector<int> vecInit1;vecInit1.resize(10);一样 for(int i=0;i<10;i++) { vecInit1.push_back(v1[i]);//将数组v1的元素添加到向量init1的最后 }
//注意,push_back每执行一次会调用一次Vector的对象vecInit1的构造函数和析构函数,效率很低啊慎用这种容器动态添加元素
第二种初始化方式: 带两个迭代器参数的构造函数
//左闭右开区间,左边从数组[0]的地址开始拷贝数组元素,到右边的数组[10]之前一个的地址结束
//也就是说如果要拷贝数组v1里的10个元素,就必须在右边,数组最后一个元素的地址再加上1(&v1[9]+1)
vector<int> vecInit2(&v1[0],&v1[9]+1);
第三种初始化方式: 默认构造函数
vector<int> vecInit3; vecInit3.reserve(10);//预先设置vector的元素容纳数量,提前预留空间 vecInit3.insert(vecInit3.begin(),&v1[0],&v1[9]+1);//后面两个参数同样也是左闭右开
第四种初始化方式: 复制构造函数
vector<int> vecInt4(vecInit3);
二.vector的三种遍历向量里元素的方式
假设有一个数组:
int v2[10] = {0,1,0,0,3,0,0,4,4,4};
vector<int> vecForeach1(&v2[0],&v2[9]+1);
第一种:.遍历向量vecForeach1的下标方式
for(int i=0;i<vecForeach1.size();i++) { printf("遍历向量vecForeach1的下标方式取vecForeach1里的元素为%d\n", vecForeach1[i]); }
第二种.使用迭代器遍历vecForeach1向量方式
for(vector<int>::iterator iter=vecForeach1.begin();iter<vecForeach1.end();iter++) { printf("使用迭代器遍历vecForeach1向量方式取vecForeach1里的元素为%d\n", *iter); }
//可以优化上面的代码
1.使用typedef vector<int>::iterator Vector_Iter将vector<int>::iterator另外定义一个名字为Vector_Iter
//2.先计算vecForeach1.end()的值,不用在for里每次都去计算一次;
//3.在for里使用iter的前置++,效率更高
//4.写算法的时候尽量使用!=比较迭代器,因为<对于很多非随机迭代器没有这个操作符
//优化后代码为:
typedef vector<int>::iterator Vector_Iter; Vector_Iter iterEnd=vecForeach1.end(); for(Vector_Iter iter=vecForeach1.begin();iter!=iterEnd;++iter) { printf("优化后的使用迭代器遍历vecForeach1向量方式取vecForeach1里的元素为%d\n", *iter); }
第三种:.使用STL的算法类里的for_each,需要包含头文件#include <algorithm>,
首先需要定义一个Vector_ForeachCoutFun的方法将元素输出
void Vector_ForeachCoutFun(int &outIndex) { printf("使用foreach输出vecForeach1里的元素为%d\n",outIndex); }
然后调用for_each将元素输出
for_each(vecForeach1.begin(),vecForeach1.end(),Vector_ForeachCoutFun);
三.vector的删除操作
1. 可以使用四种方式删除vector中的元素:
第一种是使用向量容器vector的成员函数erase(使用这种方式并不能清除删除元素所占的内存空间),由于向量容器vector中的元素在内存中都是按顺序排放的,所以删除某个元素后,会导致迭代器失效,所以或者(重新更新迭代器begin和end)或者(更新迭代器end和利用erase返回指向被删除元素的下一个元素的有效迭代器更新)这两种方式都可以使迭代器不失效;
SAMPLES:
int v3[10] = {0,1,2,3,4,5,6,7,8,9}; vector<int> vecDeleted1(&v3[0],&v3[9]+1); typedef vector<int>::iterator Vector_Iter; Vector_Iter iterEnd=vecDeleted1.end(); for(Vector_Iter iter=vecDeleted1.begin();iter!=iterEnd;++iter) { vecDeleted1.erase(iter);//使用erase迭代器失效 }
上面的代码是要依次删除vecDeleted1里的所有元素,但是会有一个问题,当删除第一个元素0后,再次遍历的时候,迭代器会报错,这就是迭代器失效造成的,所以可以使用
(更新迭代器end和利用erase返回指向被删除元素的下一个元素的有效迭代器更新)的方式更新迭代器,修改代码如下:
int v3[10] = {0,1,2,3,4,5,6,7,8,9}; vector<int> vecDeleted1(&v3[0],&v3[9]+1); typedef vector<int>::iterator Vector_Iter; //Vector_Iter iterEnd=vecDeleted1.end(); for(Vector_Iter iter=vecDeleted1.begin();iter!=vecDeleted1.end();++iter) { iter=vecDeleted1.erase(iter);//使用erase返回指向被删除元素的下一个元素的有效迭代器更新 }
将迭代器iter更新到删除元素的下一个元素,然后在for循环里使用vecDeleted1.end()代替原先的iterEnd,每次遍历的时候都更新一下vector的最末元素迭代器end()(要是不跟新这个,那么使用原先的end()指向了一个未知区域,程序当然报错)这样程序就不会报错
使用erase删除特定元素3的方式:
Vector_Iter iterVecDel=find(vecDeleted1.begin(),vecDeleted1.end(),3); if(iterVecDel!=vecDeleted1.end()) { vecDeleted1.erase(iterVecDel); }
首先使用STL算法类里的find方法,找到元素3,返回一个指向元素3的迭代器iterVecDel1,然后使用erase方法将元素3删除
思考:
如果使用erase删除了一个向量vector元素,那么其他元素在内存中是怎么移动的呢
vecDeleted1:0,1,2,3,4,5,6,7,8,9 vecDeleted1[9]==9
删除元素3后:
Vector_Iter iterVecDel=find(vecDeleted1.begin(),vecDeleted1.end(),3); if(iterVecDel!=vecDeleted1.end()) { vecDeleted1.erase(iterVecDel); }
vecDeleted1:0,1,2,4,5,6,7,8,9
那么原先vecDeleted1[9]的位置元素是什么呢,那块内存还有元素吗,答案是肯定的,由于vector使用erase删除元素时,虽然将删除的元素从向量中移走了,然后移走后面的所有元素都是很有次序的往前移了一步,那么最后一块内存里的值原先是9,9向前移了一步,那么原先的那块内存vecDeleted1[9]还是9,并没有删除那块9这个元素,所以使用erase虽然从表面上看向量vector里的元素变少了,但是实际暂用的内存可没有变少哦!切记,既然erase不能把该死的元素从内存中移除,那不是很危险,该怎么办呢,所以下面的第二种方法就能彻底的解决这个问题。
第二种是使用STL算法类里的remove函数和erase搭配的方式进行删除(此方式不用更新迭代器)(实际上在vector容器使用remove函数只是将要删除的元素放到了容器的最后,不会删除元素。在STL所有容器中,唯一一个使用remove函数做了删除操作的是list容器的remove)
SAMPLES:
int v3[10] = {0,1,2,3,4,5,6,7,8,9}; vector<int> vecDeleted1(&v3[0],&v3[9]+1); typedef vector<int>::iterator Vector_Iter; for(Vector_Iter iter=vecDeleted1.begin();iter!=vecDeleted1.end();++iter) { vecDeleted1.erase(remove(vecDeleted1.begin(),vecDeleted1.end(),*iter),vecDeleted1.end()); }
remove在一个给定范围内删除满足一定条件的元素,删除完成后,向量的大小不变,也就是说,它仅仅是将要删除的元素放到容器最后,而将所有未删除的元素前移而已。而且它返回的是指向那个移动元素位置之后的那个迭代器,所以上面的代码在使用remove之后,返回的迭代器指向向量的最后一个元素,也就是:- - vecDeleted1.end()。
然后在调用erase将向量的最后一个元素移除,由于最后一个元素后面就没有向量数据了,所以也不会往前移动任何数据,所以这样就能将向量最后一个元素移除而且还能清空这块内存。使用这种方式就没必要更新迭代器了,因为移除向量的末尾元素不会对前面的元素迭代器造成影响。只需再每次for循环更新一下end迭代器就行。
删除特定元素的方式(删除元素3):
vecDeleted1.erase(remove(vecDeleted1.begin(),vecDeleted1.end(),3),vecDeleted1.end());
第三种是使用vector的成员函数clear()(清空向量里的所有元素)
第四种是使用vector的成员函数pop_back()(移除向量里的最后一个元素)
vector删除元素总结:
1.使用erase方法不能清元素所占内存,只能将向量里的元素“表面的”移走;使用erase方法和remove方法配合使用可以真正清除向量里的元素和其所占内存,所以要删除vector里的元素就必须使用erase和remove配套使用
2.删除元素之后应该将相应的(begin迭代器,end迭代器)或(erase返回的迭代器,end迭代器)更新一下
四.vector的插入操作
第一种插入:vector的插入操作是使用vector的成员函数insert()在向量的任意位置插入一个元素,插入元素操作和删除元素的操作完成后都是需要更新失效的迭代器,有一点不同的是插入操作是一定会重新分配内存的,而删除操作是不会自动重新分配内存的,所以插入操作的迭代器是一定要更新的,和先前的迭代器不一样。
SAMPLES:
int v3[10] = {0,1,2,3,4,5,6,7,8,9}; vector<int> vecDeleted1(&v3[0],&v3[9]+1); for(Vector_Iter iter=vecDeleted1.begin();iter!=vecDeleted1.end();++iter) { iter=vecDeleted1.insert(vecDeleted1.end(),10); }
上面的iter=vecDeleted1.insert(vecDeleted1.end(),10);
insert函数返回的是指向插入新元素的迭代器iter,也就是说iter指向新插入的元素10
第二种插入:使用vector的成员函数push_back()(在向量最后添加一个元素,容器的容量也会随着扩展)
五.向量类vector的所有成员函数
1.capacity() ---vector所能容纳的元素数量(向量类vector特有的成员函数)
2.size()---vector里的实际元素个数(容器大小)
3.reserve(num)---设置vector最小所能容纳的元素数量(capacity增大num)(向量类vector特有的成员函数)
3.1 只是在堆区使用new操作符预备申请了连续的内存空间,内存里的指针未知,也未初始化该连续内存,所以不能赋值使用下标操作[0]=来添加元素,只能使用push_back()和insert()向新申请的空间添加元素
3.2 使用该方法预留空间,后面添加元素就不会不断重新分配内存
4.resize(num)---改变vector容器的大小(size增大num,capacity线性增大)
4.1 申请了内存空间和空间中的指针,可以使用下标操作[0]=来添加元素(不会分配内存),也能使用push_back()(会重新分配内存)和insert()(在向量vector的末尾插入新元素会重新分配内存)
4.2 使用该方法不断的改变容器大小会重新分配内存,效率很低
注意:如果向量vector原本里头就有元素,那么使用reserve和resize都不会对向量里原本的元素造成影响,也就是原来向量的元素还是存在
SAMPLES:
vector<int> vecMembers1; vecMembers1.reserve(10); vecMembers1.size();//0 vecMembers1.capacity();//10 vecMembers1.insert(vecMembers1.begin(),0);//在第0个元素之后插入元素0 vecMembers1.insert(vecMembers1.end(),1);//在第1个元素之后插入元素1 vecMembers1.push_back(2);//在第2个元素之后插入元素2 vecMembers1.size();//3 vecMembers1.capacity();//10 vecMembers1.resize(100); vecMembers1.size();//100 vecMembers1.capacity();//100 vecMembers1[3]=3; vecMembers1.insert(vecMembers1.end(),4);//在第100个元素之后插入元素4 vecMembers1.push_back(5);//在第101个元素之后插入元素5 vecMembers1.size();//102 vecMembers1.capacity();//150