原本以为自己掌握了vector,但其实只是掌握了vector的访问,特别是删除操作返回的是一个迭代器,却容易和Python的remove()直接删除元素混淆,没有理解透彻,因此在这里总结一下vector的基本用法。
vector应该是STL种最常用的容器了,可以当做数组来看待,只不过vector的元素更丰富,不仅仅是数据元素,还可以是结构体
1、vector的创建和初始化
vector <double> v;//创建一个double类型的vector vector <int> v2(5);//创建一个含有5个元素的int型vector,初始值默认为0 vector <int> v3(4,7);//创建一个含有4个元素的int型vector,初始值都为7
当然也可以通过在尾部添加元素来初始化
vector <double> v; v.push_back(3.5); v.push_back(4.9); v.push_back(1.5);//其中v[0] = 3.5 v[1] = 4.9 v[2] = 1.5
2、vector的元素遍历
vector <double> v; v.push_back(3.5); v.push_back(4.9); v.push_back(1.5); //下标访问 for(int i = 0; i < v.size();i++) { cout << v[i] << endl; } //const迭代器访问 for(vector <double>::const_iterator it = v.begin(); it !=v.end();it++) { cout << *it << endl; } //非const迭代器访问 for(vector <double>::iterator it = v.begin(); it !=v.end();it++) { cout << *it << endl; } //逆序访问,同样分为const和非const for(vector <double>::reverse_iterator it = v.rbegin(); it !=v.rend();it++) { cout << *it << endl; }
说明一下,其中的const和非const迭代器在访问元素时没有区别,只是非const迭代器可以通过*it = value来改变vector元素的值
3、vector的插入操作
v.insert(v.begin()+2,5); //在索引为2(从0开始)的位置插入元素5 v.insert(v.begin(),2,3);//在索引为0的位置插入2个值为3的元素
4、vector的删除
v.erase(v.begin()+i);//删除索引为i的元素 v.erase(vec.begin()+i,vec.end()+j);删除区间[i,j-1];区间从0开始
v.pop_back();//删除尾部元素 v.clear();//删除所有元素
举个例子,删除double类型的vector中与指定值key相等的元素,并统计个数,其实统计个数可以用 int n = count(v.begin(),v.end(),key) 返回的就是个数,count头文件是<alogrithm>
vector <double> v; v.push_back(3.5); v.push_back(4.9); v.push_back(1.5); v.push_back(3.5); v.push_back(3.5); v.push_back(4.9); v.push_back(3.5); double key = 3.5; const double MIN = 0.00000001; //索引删除 for(int i =0; i<v.size();i++) { if((v[i] - key < MIN) && (v[i] -key > -MIN)) //double类型,需要定义一个精度 { v.erase(v.begin()+i); i--;//假设[2,3,4]删除元素3,其索引为2,删除3后,元素4成了索引2对应的值,所以减一 cnt++; } } //或者用迭代器删除 for(it = v.begin();it != v.end();) { if((*it - key < MIN) && (*it -key > -MIN)) { it = v.erase(it); //删除函数返回的是下一个元素的迭代器 cnt++; } else { it++; } } //使用算法删除,remove函数后会获取删除key后迭代器的位置,此时位于新序列的结尾,该位置距离原始序列的结尾还差删除的key的个数的距离,因此再earse最后几个空位置 v.erase(remove(v.begin(),v.end(),key),v.end());
5、相关的算法
reverse(vec.begin(),vec.end()); //将元素翻转 sort(vec.begin(),vec.end()); //默认升序排列 bool cmp(const int &m, const int &n) { return a > b; } sort(vec.begin(),vec.end(),cmp); //根据cmp排序,这里是
6、vector的内存分配
vector其实维护着三个指针
template <typename T> class vector { ... private: T* first; T* last; T* end; };
由于没法上图片,这里就简单解说一下吧,创建一个vector时,三个指针均指向同一个位置,当用push_back添加元素时,first指向首元素,last指向尾元素,而end则指向vector.capacity,也就是可以容纳的最大元素个数的索引位置,而这个容量是成指数增加的,添加第1个元素,可容纳1个元素,然后添加第2个元素,此时容器大小为2,然后添加第3个元素,此时容器大小会增加2,变为4,而不是3,添加第4个元素时,由于容器大小为4,可容纳,此时容器大小不变,当添加第5个元素时,容器大小就增加到8了,我理解这是一种策略,不然每次添加一个元素,容器都增加一个空间,增加空间实际上是将原来的内存空间拷贝到了另一个内存空间,过度频繁拷贝导致效率低,所以才成指数级增加,尽管这样,但是拷贝还是很多,效率还是挺低的,不过用起来很方便。所以可以理解为first到last之间的元素为vector实际存储的元素,first到end是vector的可用空间大小。