[vector文档](vector - C++ Reference (cplusplus.com))
vector
是序列容器,表示可以改变大小的数组。要使用vector
,同样需要引入头文件
#include <vector>
vector与string
string
中会有\0
,vector<char>
中不会出现\0
string
可以进行字符串的拼接,vector<char>
不可以
vector的构造
void test1() { vector<int> v1; v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); cout << "v1:"; for (size_t i = 0; i < v1.size(); ++i) { cout << v1[i] << " "; } cout << endl; vector<int> v2(v1); cout << "v2:"; for (size_t i = 0; i < v2.size(); ++i) { cout << v2[i] << " "; } cout << endl; }
vector的3种遍历方式
operatro[]、迭代器、范围for
void test2() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); //operator[] for (size_t i = 0; i < v.size(); ++i) { cout << v[i] << " "; } cout << endl; //迭代器 vector<int>::iterator it = v.begin(); while (it != v.end()) { cout << *it << " "; ++it; } cout << endl; //范围for for (auto x : v) { cout << x << " "; } cout << endl; }
3种类型的迭代器
void test3() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); //正向迭代 可读可写 vector<int>::iterator it = v.begin(); while (it != v.end()) { cout << *it << " "; ++it; } cout << endl; //逆向迭代 vector<int>::reverse_iterator rit = v.rbegin(); while (rit != v.rend()) { cout << *rit << " "; ++rit; } cout << endl; } //只读 void print_vector(const vector<int>& v) { vector<int>::const_iterator it = v.begin(); while(it != v.end()) { //*it = 1; cout << *it << " "; ++it; } cout << endl; }
const
迭代器单独放到一个函数中,是因为只有const
对象才需要const
迭代器,在实际中不会直接定义const
对象(没有意义),const
对象基本都是在传参的过程中产生的,由于传参为了提高效率,基本都会使用&
传参,而引用传参如果不改变对象,基本都会加const
。
容量相关
// 测试vector的默认扩容机制 void TestVectorExpand() { size_t sz; vector<int> v; sz = v.capacity(); cout << "making v grow:\n"; for (int i = 0; i < 100; ++i) { v.push_back(i); if (sz != v.capacity()) { sz = v.capacity(); cout << "capacity changed: " << sz << '\n'; } } }
从上面可以看出,随着数据的不断插入,增容的速度越来越慢,并且是按照1.5倍进行增容,但并不是说vector都是按照1.5倍进行增容,具体增容多少是和编译器的不同而有所改变。
还有就是增容的倍数并不是越大越好,倍数越大虽然可以减少增容的次数,但是有可能会导致浪费大量的空间。因此增多少是一种选择,各有利弊。若是已经确定要存储元素的个数,可以提前将空间设置足够
void TestVectorExpandOP() { vector<int> v; size_t sz = v.capacity(); v.reserve(100); // 提前将容量设置好,可以避免一遍插入一遍扩容 cout << "making bar grow:\n"; for (int i = 0; i < 100; ++i) { v.push_back(i); if (sz != v.capacity()) { sz = v.capacity(); cout << "capacity changed: " << sz << '\n'; } } }
insert()与erase()
void test5() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.insert(v.begin(), 0); v.insert(v.begin(), -1); for (auto x : v) { cout << x << " "; } cout << endl; v.erase(v.begin()); for (auto x : v) { cout << x << " "; } cout << endl; }
在上面中,erase并不能删除指定的数据,而vector中并没有find函数,所以此时我们需要引入
algorithm
,#include<algorithm>
。//要求删掉2 vector<int>::iterator pos = find(v.begin(), v.end(), 2); if (pos != v.end()) { v.erase(pos); } for (auto x : v) { cout << x << " "; } cout << endl;
find
其实是一个函数模板,如下template<class InputIterator, class T> InputIterator find(InputIterator first, InputIterator last, const T& val) { while (first != last) { if (*first == val) return first; ++first; } return last; }
迭代器失效
标签:const,cout,迭代,back,vector,push From: https://www.cnblogs.com/zhiheng-/p/18185452迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)
引起底层空间改变的操作,迭代器可能失效
void test6() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); //迭代器失效 vector<int>::iterator it = v.begin(); v.push_back(5); v.push_back(6); while (it != v.end()) { cout << *it << " "; ++it; } cout << endl; }
从上面来看,由于在插入
5
、6
的之前it
已经被赋值,当插入5
、6
时,由于空间不够,需要开辟新的空间,销毁原来的空间,而it
任然指向的是原来的那个空间,因此此时的迭代器就已经失效了。删除操作——erase
void test7() { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.push_back(6); vector<int>::iterator it = v.begin(); for (auto x : v) { cout << x << " "; } cout << endl; //删除偶数 while (it != v.end()) { if (*it % 2 == 0) { v.erase(it); } else { ++it; } } for (auto x : v) { cout << x << " "; } cout << endl; }
在上面代码中,由于使用
erase
删除pos
位置元素的时候,pos
之后的元素会向前移动,此时的it
没有改变,但是it所指向的元素发生了变化,变成了原来pos+1
位置的元素,此时程序就崩溃了。而之后又要进行++it
,因此就会漏掉对此时it所指向元素的判断。注意:在vscode中以上写法会导致程序崩溃,但在linux下的g++中,以上写法并不会崩溃,只是最后的结果会出错。
因为erase返回的是被删除元素后一个位置的迭代器,所以正确的写法如下
while (it != v.end()) { if (*it % 2 == 0) { it = v.erase(it); } else { ++it; } }