# 0 vector
vector是数据库提供的容器之一,本质上是顺序表。
内部成员变量是三个所存储数据类型的指针。
// 分别是:
iterator _start; // 指向数据空间的开始
iterator _finish; // 指向最后一个有效数据的下一个位置
iterator _endOfStorage; // 指向存储容量的尾
要使用vector,需要包含头文件:
#include <vector>
vector是一个类模板,使用时需要显式实例化,
指明内部存储的数据类型。
// 例如:
vector<int> v1;
vector<double> v2;
vector<string> v3;
# 1 迭代器
vector的迭代器就是原生的指针。
这是因为vector本质上是顺序表,底层空间是连续的。
为了规范,为了与所有的容器保持一致,
内部都将迭代器类型重命名为iterator,
const对象的迭代器重命名为const_iterator。
反向迭代器等,下面就不提了。
# 1.1 begin()
支持const与非const对象调用。
返回指向数据空间起始位置的迭代器。
# 1.2 end()
支持const对象与非const对象调用。
返回指向最后一个有效数据的下一个位置的迭代器。
对这个位置的迭代器解引用是没有意义的,可能是无效的数据,甚至可能越界。
# 2 默认成员函数
# 2.1 构造函数
共有三种构造函数。
分别是无参的构造函数;
创建有n个有效数据,并初始化为value的构造;
用一个迭代器区间来构造。
# 2.1.1 无参的默认构造
vector<int> v1;
for (auto e : v1)
{
cout << e;
}
cout << endl;
这样创建出来的vector没有有效数据。
直接访问内部数据自然是什么都没有。
可以很方便的进行后续操作。
# 2.1.2 初始化n个数据的构造
传两个参数,第一个是有效数据的个数,第二个是用于初始化这些有效数据的值。
第二个参数有缺省值,为value_type()。
意思是调用该数据类型的默认构造来初始化。
为了使内置类型与类类型匹配格式,所以给内置类型也加上了默认构造。
具体是什么不重要,总之有就对了。
vector<int> v2(10, 3);
for (auto e : v2)
{
cout << e;
}
cout << endl;
# 2.1.3 迭代器区间构造
用一个迭代器区间来初始化,这个迭代器区间并不局限于vector的迭代器,也可以是其他容器的。
vector<int> v2(10, 3);
vector<int> v3(v2.begin(), v2.end());
for (auto e : v3)
{
cout << e;
}
cout << endl;
# 2.2 拷贝构造
拷贝构造也算在构造函数内,这里第四个就是拷贝构造。
用另一个vector类型的对象来初始化。
vector<int> v1(10, 5);
vector<int> v2 = v1;
for (auto e : v2)
{
cout << e;
}
cout << endl;
# 2.3 赋值重载
两个已经存在的vector类型对象,用一个赋值给另一个。
vector<int> v1(10, 9);
vector<int> v2;
v2 = v1;
for (auto e : v2)
{
cout << e;
}
cout << endl;
# 2.4 析构函数
vector的析构会释放开出来的这一块顺序表的空间。
没有什么可说的。
# 3 容量相关函数
# 3.1 size
返回对象内有效数据的个数。
# 3.2 capacity
返回对象内最大可存储有效数据的个数。
# 3.1 reserve
调整对象容量大小,如果目标容量小于原本容量,根据编译环境的不同,可能会缩小容量,或者是什么都不做。
如果大于原本容量,就会讲容量扩大至至少目标容量的大小,根据编译环境的不同,可能会更大。
无论哪种,reserve行为都不会影响有效数据。
void Test6()
{
vector<int> v(10, 7);
cout << v.size() << endl;
cout << v.capacity() << endl;
for (auto e : v)
{
cout << e;
}
cout << endl << endl;
// 目标容量大于原容量
v.reserve(20);
cout << v.size() << endl;
cout << v.capacity() << endl;
for (auto e : v)
{
cout << e;
}
cout << endl << endl;
// 目标容量小于原容量
v.reserve(3);
cout << v.size() << endl;
cout << v.capacity() << endl;
for (auto e : v)
{
cout << e;
}
cout << endl << endl;
}
可以看到,有效数据始终没有变化;
目标容量大于原容量时扩容,否则容量不变。
# 3.1 resize
resize支持传两个参数。
第一个参数指定目标有效数据个数,有三种情况:
1.目标size小于原size:
会发生截断,只保留原有效数据的前目标size个。
2.目标size大于原size,小于等于原capacity:
空间足够,那么会填充数据,直至个数达到目标size,
用于填充的值就是第二个参数。
这个参数可以缺省,会调用数据类型的构造函数。
3.目标size大于原capacity:
这种情况就会扩容了,扩容完成后就相当于是第二种情况了,
会用第二个参数去填充。
void Test7()
{
vector<int> v(10, 8);
cout << v.size() << endl;
cout << v.capacity() << endl;
for (auto e : v)
{
cout << e;
}
cout << endl << endl;
v.resize(3);
cout << v.size() << endl;
cout << v.capacity() << endl;
for (auto e : v)
{
cout << e;
}
cout << endl << endl;
v.resize(7);
cout << v.size() << endl;
cout << v.capacity() << endl;
for (auto e : v)
{
cout << e;
}
cout << endl << endl;
v.resize(11);
cout << v.size() << endl;
cout << v.capacity() << endl;
for (auto e : v)
{
cout << e;
}
cout << endl << endl;
}
最后扩容的时候,到底扩容到多少是由编译器决定的,和前面提到的一样,并不一定是开的正好,可能会更大,就像这里。
# 4 内部数据访问与修改函数
# 4.1 [ ]重载
[ ]重载是vector最大的优势,能够随机且高效的访问数据。
void Test8()
{
vector<int> v(10, 1);
for (size_t i = 0; i < v.size(); ++i)
{
cout << v[i] << " ";
}
}
# 4.2 尾插push_back
尾插是vector增加数据最常用的,也是最有效率的。
空间不足时,会自动扩容。
void Test9()
{
vector<int> v(3, 4);
cout << v.size() << endl;
cout << v.capacity() << endl;
for (auto e : v)
{
cout << e << " ";
}
cout << endl << endl;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
v.push_back(60);
cout << v.size() << endl;
cout << v.capacity() << endl;
for (auto e : v)
{
cout << e << " ";
}
cout << endl << endl;
}
# 4.3 尾删pop_back
简单从尾部删除数据,改变size,不改变capacity。
void Test9()
{
vector<int> v(3, 4);
cout << v.size() << endl;
cout << v.capacity() << endl;
for (auto e : v)
{
cout << e << " ";
}
cout << endl << endl;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
v.push_back(60);
cout << v.size() << endl;
cout << v.capacity() << endl;
for (auto e : v)
{
cout << e << " ";
}
cout << endl << endl;
v.pop_back();
v.pop_back();
v.pop_back();
cout << v.size() << endl;
cout << v.capacity() << endl;
for (auto e : v)
{
cout << e << " ";
}
cout << endl << endl;
}
# 4.4 交换swap
简单的交换两个vector类型的对象。
没什么好说的。
# 4.5 任意位置插入insert
insert有三种重载:
1.在指定迭代器位置position插入数据val;
2.在指定迭代器位置position插入n个数据val;
3.在指定迭代器位置position插入一段迭代器区间内的数据。
void Test10()
{
vector<int> v(5, 2);
for (auto e : v)
{
cout << e << " ";
}
cout << endl << endl;
// 起始位置插入
v.insert(find(v.begin(), v.end(), 2), 20);
// 中间位置插入
v.insert(find(v.begin(), v.end(), 2), 30);
v.insert(find(v.begin(), v.end(), 2), 4, 40);
for (auto e : v)
{
cout << e << " ";
}
cout << endl << endl;
}
# 4.6 任意位置删除erase
两种重载:
1.删除目标迭代器位置的数据;
2.删除一段迭代器区间内的数据。
void Test10()
{
vector<int> v(5, 2);
for (auto e : v)
{
cout << e << " ";
}
cout << endl << endl;
// 起始位置插入
v.insert(find(v.begin(), v.end(), 2), 20);
// 中间位置插入
v.insert(find(v.begin(), v.end(), 2), 30);
v.insert(find(v.begin(), v.end(), 2), 4, 40);
for (auto e : v)
{
cout << e << " ";
}
cout << endl << endl;
// 头删
v.erase(find(v.begin(), v.end(), 20));
v.erase(find(v.begin(), v.end(), 40), find(v.begin(), v.end(), 2));
for (auto e : v)
{
cout << e << " ";
}
cout << endl << endl;
}