第五讲我们讲了string,这一讲开始,我要引入一个新的stl容器,vector也就类似于数据结构的顺序表。
首先讲一下vector的构造方法。

从上到下,分别对应默认构造、用n个字符填充数组的构造、利用迭代器构造、以及拷贝构造,我先讲前三个传统的构造。
cpp
void test_vector_init()
{
//默认构造
vector<int> v;
//n个元素构造
vector<int> v1(10, 8);
//迭代器构造
vector<int> v2(++(v1.begin()), --(v1.end()));
}

从字面意思就很好理解这三个构造方法,但是从中我们可以提取到一些关键信息,首先,vector的成员变量主要是数组+capacity+size三个,这三个成员变量可以维护数组的大部分信息。
此外,vector也支持迭代器,我接下来讲一讲迭代器以及遍历。

和string区别并不大,vector的迭代器种类也是这四组,分别是begin/rbegin/cbegin/crbegin。我这里就begin/end做一个演示。
cpp
for (int i = 0; i < v1.size(); i++)
{
cout << v1[i] << " ";
}
cout << endl;
vector<int>::iterator it1 = v1.begin();
while (it1 != v1.end())
{
cout << *it1 << " ";
it1++;
}
cout << endl;
for (auto e : v1)
{
cout << e << " ";
}
cout << endl;

结合三组遍历方式,首先我们可以发现iterator在vector中的使用和string基本是没区别的,此外,上述代码传递了些许信息,首先,我没用cout<<v1直接对数组进行打印,因为vector并没有重载<<,>>两个流操作符,此外我使用了\[\]访问数组元素,也进而说明vector重载了\[\]操作符。
接下来是这一组

size不必多说,返回当前数组元素个数,capacity也类似,返回当前数组空间大小,empty返回当前数组是否为空。
其中比较需要讲解的是resize和reserve

vector中的reserve和string中的略有不同

这段话是说,当你给reserve传一个大于当前容量的值时,会对数组进行扩容,除此之外不会对空间有任何影响。
和string中的reserve不同的是,string对于n小于capacity的情况是不做要求的,虽然在vs中并没有实现缩容,但不代表不可以这么做,但vector就已经限定死了。
此外reserve不会对原来元素进行修改。
cpp
void test_vector_reserve()
{
vector<int> v(10, 8);
cout << v.capacity() << endl;
cout << v.size() << endl;
v.reserve(20);
cout << v.capacity() << endl;
cout << v.size() << endl;
v.reserve(15);
cout << v.capacity() << endl;
cout << v.size() << endl;
v.reserve(5);
cout << v.capacity() << endl;
cout << v.size() << endl;
}

接下来是resize

和string使用方法别无二致,规则也没什么区别,这里不做讲解,详情请参考上一讲。
cpp
void test_vector_resize()
{
vector<int> v(10, 8);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
cout << v.capacity() << endl;
cout << v.size() << endl;
v.reserve(20);
cout << v.capacity() << endl;
cout << v.size() << endl;
v.resize(15, 9);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
cout << v.capacity() << endl;
cout << v.size() << endl;
v.resize(5);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
cout << v.capacity() << endl;
cout << v.size() << endl;
}

接下来,我对vector的插入做一个讲解

插入主要用的是push_back和insert,我先讲一下push_back尾插

push_back尾插需要注意的是,只能尾插一个元素,如果空间不够数组会自行扩容。
cpp
void test_vector_push_back()
{
vector<int> v(10, 8);
v.reserve(20);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
cout << v.capacity() << endl;
cout << v.size() << endl;
for (int i = 0; i < 20; i++)
{
v.push_back(i);
/*cout << v.capacity() << endl;
cout << v.size() << endl;*/
}
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
cout << v.capacity() << endl;
cout << v.size() << endl;
}

vector的扩容逻辑和string类似,也是1.5倍扩容。
接下来讲一下insert

和string不同的一点是,vector中的insert不再支持下标传参,只能传迭代器。
cpp
void test_vector_push_back()
{
vector<int> v(10, 8);
v.reserve(20);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
cout << v.capacity() << endl;
cout << v.size() << endl;
for (int i = 0; i < 20; i++)
{
v.push_back(i);
/*cout << v.capacity() << endl;
cout << v.size() << endl;*/
}
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
cout << v.capacity() << endl;
cout << v.size() << endl;
}
void test_vector_insert()
{
vector<int> v(10, 8);
vector<int>::iterator it = v.begin();
v.insert(it, 100);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
it = v.begin();
v.insert(it + 3, 4, 99);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
vector<int> v1(6, 6);
it = v.begin();
v.insert(it + 1, v1.begin() + 1, v1.begin() + 4);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
string s1("aaaaaaa");
it = v.begin();
v.insert(it + 1, s1.begin() + 1, s1.begin() + 4);
for (auto e : v)
{
cout << e << " ";
}
cout << endl;
}
有几点需要注意,首先,当你扩容后需要重新指定迭代器,不然指向的还是原先空间,其次string类也可以利用第三种插入方式插入到vector中,只不过是ASCII码值。
本质insert还是挪动数组,所以谨慎使用,保不齐会影响效率。
最后,我讲一下关于vector的模板参数,首先类模板需要显式实例化。
其次vector的模板参数可以是vector也可以是string等自定义类型
cpp
void test_vector_p()
{
vector<string> v;
for (int i = 0; i < 10; i++)
{
v.push_back("hello world");
}
for (auto e : v)
{
cout << e << " ";
cout << endl;
}
cout << endl;
vector<vector<int>> v1;
for (int i = 0; i < 5; i++)
{
vector<int> v2(i + 1, i);
v1.push_back(v2);
}
for (auto e : v1)
{
for (auto k : e)
{
cout << k << " ";
}
cout << endl;
}
cout << endl;
cout << v1[2][2] << endl;
}

有点像二维数组。
关于vector的使用我就先讲到这,后续还会接着补充。