写在前面
标准库类型vector表示对象的集合, 其中所有对象的类型都相同. 集合中的每个对象都有一个与之对应的索引, 索引用于访问对象.
因为vector "容纳着"其他对象, 所以它也被称为容器.
使用vector需要导入vector头文件:
include <vector>
using namaspace std;
构造
语法形式:
vector 变量名; //T为数组中元素的类型
一些常见的构造如下:
vector<int> vec; //初始化一个大小, 容量均为0的vector对象
vector<string> sVec; //可为其他类型
vector<diyType> xVec; //甚至自定义类型
//列表初始化
vector<int> nVec = { 1, 2, 3 };
vector<string> sVec{ "1", "12", "123" };
vector<int> nVec2(initializer_list<int>{1, 2, 3}); //C++11标准提供的
//带参构造
vector<int> nVec3(10, 1); //构造一个大小为10, 容量为10, 各元素初始值为1的vector对象, 一般用于希望初始化后可直接使用下标访问的常见
vector<int>::size_type nVec2Size = nVec2.size();
vector<int>::size_type nVec2Capacity = nVec2.capacity();
vector<int> nVec4(nVec3); //拷贝构造, 注意两个vector对象的类型必须一致.
vector<int> nVec5 = nVec4; //赋值构造, 注意两个vector对象的类型必须一致.
初始化列表initializer_list可参考:初始化列表
size_type类型
同string一样, 暂无法得知其具体细节, 但可知它是一个无符号类型.
使用时需要注意, 应习惯性的声明当前类型对应的size_type对象.
vector<int> nVec{1, 2, 3};
vector<int>::size_type nSize = nVec.size();
//虽然可以但不建议这样
vector<string> sVec(1, "1");
vector<int>::size_type nSize = sVec.size();
容器大小容量
size成员函数
size成员函数返回容器中的元素数量.
函数原型:
size_type size() const;
vector<int> nVec{1, 2, 3};
vector<int>::size_type nSize = nVec.size(); //size = 3
empty成员函数
判断容器是否为空, 为空返回true, 否则返回false。
//函数原型
bool empty() const;
vector<string > sVec;
if ( sVec.empty() )
{
//容器为空
}
capacity成员函数
返回当前容器容量, 即在不分配更多的存储的情况下容器可以包含的元素数。
注意: size会小于等于capacity.
//函数原型
size_type capacity() const;
vector<int> nVec(10, 0); //初始size为10, 初始容量为10
vector<int>::size_type nCap = nVec.capacity();
resize成员函数
为容器指定新的大小。
//函数原型
//new_size: 新指定的容器大小
//value: 新size大于旧size时添加到容器的新元素的初始化值。 如果省略该值,则新对象(类型为Type)将使用其默认构造函数。
void resize(size_type new_size);
void resize(size_type new_size, Type value);
注意:
- 当新size 等于 旧size时, 这里不执行任何操作
- 当新size 大于 旧size时, 会向容器中添加新元素(初始值如上描述)至新size大小, 如果新size超出当前容量, 会动态扩容, 内存地址会变更
- 当新size 小于 旧size时, resize 将删除最接近容器末尾的元素,直到达到新size为止。
vector<int> nVec = { 1, 2, 3 };
vector<int>::size_type nVecSize = nVec.size();
vector<int>::size_type nVecCapacity = nVec.capacity();
cout << "初始状态, size: " << nVecSize << " , capacity: " << nVecCapacity << endl;
nVec.resize(5, 666);
nVecSize = nVec.size();
nVecCapacity = nVec.capacity();
cout << "新size > 旧size, size: " << nVecSize << " , capacity: " << nVecCapacity << endl;
nVec.resize(1, 666);
nVecSize = nVec.size();
nVecCapacity = nVec.capacity();
cout << "新size < 旧size, size: " << nVecSize << " , capacity: " << nVecCapacity << endl;
reserve成员函数
为容器保留最小的容量,必要时为其分配空间。
//函数原型
void reserve(size_type count);
vector<int> nVec2(initializer_list<int>{1, 2, 3}); //C++11标准提供的初始化列表
vector<int>::size_type nVec2Size = nVec2.size();
vector<int>::size_type nVec2Capacity = nVec2.capacity();
cout << "reserve前初始状态, size: " << nVec2Size << " , capacity: " << nVec2Capacity << endl;
nVec2.reserve(5);
nVec2Size = nVec2.size();
nVec2Capacity = nVec2.capacity();
cout << "reserve 新容量 > 旧容量, size: " << nVec2Size << " , capacity: " << nVec2Capacity << endl;
nVec2.reserve(1);
nVec2Size = nVec2.size();
nVec2Capacity = nVec2.capacity();
cout << "reserve 新容量 < 旧容量 且 新容量 < 当前size, size: " << nVec2Size << " , capacity: " << nVec2Capacity << endl;
还需注意的是使用reserve预留容量后, 并不代表size也会变为该大小.
vector<int> nVec; //初始化一个size 为0, 容量为0 的vector对象
nVec.reserve(10); //预留10个int大小的内存, 此时容量为10, 但size依旧为0
nVec[5] = 0; //错误: 非法下标访问
nVec.resize(10, 666);
nVec[5] = 0; //正确: 此时0 - 9均为合法下标
小结
resize和reserve成员函数指定的新大小或新容量在大于当前最大容量时, 都会动态扩容, 并未另外找一块更大的内存并将所有元素拷贝到新内存中后, 删除原来小的内存.
赋值操作
vector提供三种赋值操作, 需注意赋值对象类型应该一致.
vector<int> nVec{1, 2, 3};
//assign成员函数
vector<int> nVec2;
nVec2.assign(nVec.begin(), nVec.end());
//等号运算符
vector<int> nVec3;
nVec3 = nVec;
//swap成员函数: 交换两个vector对象中的元素
vector<int> nVec4;
nVec4.swap(nVec); //交换过后, nVec4的size为3, 容量为3, 而nVec的size为0, 容量为0
访问操作
vector<int> nVec{1, 2, 3};
//使用at成员函数访问容器元素
//注意: 如果下标非法, 则引发异常。
int nNum = nVec.at(1); //返回2
//使用下标运算符, 下标非法, 则引发异常
int nNum2 = nVec[1]; //返回2
//front, back成员函数
int nFrontNum = nVec.front(); //返回1
int nBackNum = nVec.back(); //返回3
遍历vector对象中元素:
vector<int> nVec{1, 2, 3, 4, 5};
//for语句遍历: 保证下标合法性
for (vector<int>::size_type i = 0; i < nVec.size(); i++)
{
cout << nVec[i] << endl;
}
//C++11新标准提供范围for语句
for (auto n : nVec)
{
cout << n << endl;
}
//使用迭代器遍历
for (auto it = nVec.begin(); it != nVec.end(); it++)
{
cout << *it << endl;
}
for (vector<int>::iterator it = nVec.begin(); it != nVec.end(); it++)
{
cout << *it << endl;
}
插入操作
insert成员函数
在指定位置添加指定数量的指定元素.
函数原型:
iterator insert(
const_iterator position,
const Type& value);
iterator insert(
const_iterator position,
Type&& value);
void insert(
const_iterator position,
size_type count,
const Type& value);
template <class InputIterator>
void insert(
const_iterator position,
InputIterator first,
InputIterator last);
//参数解析
//position: 向量中插入第一个元素的位置。
//value: 插入到向量中的元素的值。
//count: 插入向量中的元素数目。
//first: 要复制的范围元素中的第一个元素的位置。
//last: 要复制的元素范围以外的第一个元素的位置。
//返回值: 前两个 insert 函数返回一个指定新元素插入到向量的位置的迭代器。
示例:
vector<int> nVec;
nVec.insert(nVec.begin(), 1); //nVec[0] = 1;
nVec.insert(nVec.begin(), 2); //nVec[0] = 2; nVec[0] = 1;
nVec.insert(nVec.begin(), 3, 6); //nVec = { 6, 6, 6, 2, 1};
vector<int> nVec2;
nVec2.insert(nvec2.begin(), nVec.begin(), nVec.end()); //nVec2 = { 6, 6, 6, 2, 1};
push_back成员函数
在容器末尾处添加一个元素。
函数原型如下:
void push_back(const T& value);
vector<int> nVec;
nVec.push_back(1);
nVec.push_back(2);
nVec.push_back(3);
删除操作
pop_back成员函数
删除容器末尾处的元素。
注意: 不可对空vector对象调用pop_back函数, 否则会引发异常
//函数原型
void pop_back();
vector<int> nVec;
//nVec.pop_back(); //不可对空vector调用pop_back, 会引发异常
nVec.push_back(1);
nVec.push_back(2);
nVec.push_back(3);
nVec.pop_back(); //nVec = { 1, 2 };
erase成员函数
从指定位置删除容器中的一个元素或一系列元素。
//函数原型
iterator erase(
const_iterator position);
iterator erase(
const_iterator first,
const_iterator last);
//position: 要从向量中移除的元素的位置。
//first: 要从向量中移除的第一个元素的位置。
//last: 紧接要从向量中移除的最后一个元素的位置
vector<int> nVec{ 1, 2, 3, 4, 5};
nVec.erase(nVec.begin()); //删除第一个元素, 删除后nVec = { 2, 3, 4, 5}
//nVec.erase(nVec.end()); //错误: nVec.end()指向最后一个元素的后一个位置, 这里会引发异常
nVec.erase(nVec.begin(), nVec.end()); //删除所有元素
vector的动态机制
普通数组在声明时必须指定内存大小, 而vector被称为动态数组, 是因为vector能根据当前的size和容量来动态的扩大或缩小其内存大小.
这里注意动态的内存分配并不是, 而是找一个新的内存空间, 将原有数据拷贝到新内存空间下, 然后释放掉原有内存, 以此来实现动态的特性.
而每次新分配的内存大小为旧内存大小的1.5倍(或2倍).
vector<int> nVec10(10, 1);
cout << "起始状态--vector对象地址: " << &nVec10 << ", 内部元素集合起始地址: " << &nVec10[0] << ", 容量: " << nVec10.capacity() << endl;
nVec10.insert(nVec10.begin(),666); //这里插入操作会动态扩容, 新内存大小为之前的1.5倍
cout << "insert后--vector对象地址: " << &nVec10 << ", 内部元素集合起始地址: " << &nVec10[0] << ", 容量: " << nVec10.capacity() << endl;