vector 容器是数组的最佳替代者
vector 容器同样可以用于保存和管理大量同类型数据,但无论是在内存管理上还是在对数据元素的访问上,都要优于数组:
vector 容器动态增减的容量大小替代了数组的固定容量,可以适应各种不同的需要;
通过 vector 容器提供的功能函数操作数据元素替代了数组通过“[]”对数据元素的直接操作,不仅更加安全,同时还提供了更丰富的操作。
因此 vector 容器也成为了数组的最佳替代者,是我们最为常用的 STL 容器。
创建并初始化 vector 对象
vector 容器是一个类模板 vector,因此要想使用 vector 容器,首先需要根据我们想要保存数据的类型实例化得到一个特定类型的模板类,然后创建相应的 vector 容器对象,最后就可以利用它提供的功能函数,对容器进行添加、删除、插入等常见操作,完成对数据的管理。
空容器初始化
#include <vector> // 引入 vector 类模板所在的头文件
using namespace std; // 使用 vector 所在的名字空间 std
// …
// 因为要保存 Employee 对象,先使用 Employee 类型实例化 vector 类模板,
// 然后创建实例对象 vecEmp
vector<Employee> vecEmp;
带有默认数据的初始化
指定默认数据及默认数据的个数
如果想得到一个已经保存有默认数据的 vector 容器,则可以在创建容器对象的时候,利用其构造函数指定默认数据及默认数据的个数。当容器对象创建完成时,这些默认数据也就已经保存在容器中了。
Employee emp; // 默认数据
// 创建 4 个 emp 对象的副本保存到容器中
vector<Employee> vecEmp(4, emp);
// 使用 Employee 类的默认构造函数创建 4 个对象保存到容器中
vector<Employee> vecDefEmp(4);
利用初始化列表
// 创建一个保存学生成绩的 vector 容器
// 在创建的同时利用初始化列表添加初始数据
vector<int> vecScores = { 87, 72, 63, 93 };
reserve()函数申请足够的内存
如果已经预先知道 vector 容器可能的最大容量,则可以使用 reserve()函数申请足够的内存,为 vector 容器预留足够多的元素位置,减少在元素添加过程中内存的动态申请过程。
// 大约有 1000 位员工,所以为 vector 容器预留 1000 个元素位置
vecEmp.reserve( 1000 );
array 容器
要保存一组固定个数相同类型的数据,例如一年 12 个月的平均气温、一周 7 天的 PM 2.5数值等。在这种情况下,如果仍旧使用 vector 容器来存放这些数据, vector 容器的动态内存往往会申请比实际保存数据所需的更多的空间,这样会浪费宝贵的内存资源; vector 容器提供了 push_back()函数可以动态地向容器中添加数据,如果无意中调用了 push_back()函数,就会破坏这组数据的固定个数。既要利用容器的各种优势,又要避免 vector 容器在保存这类数据时的各种劣势, STL 提供了 vector 容器的备胎——array容器。
array 是一个支持随机访问且大小固定的容器。跟 vector 容器为元素预留空间不同, array 容器并不预留多余空间,只为元素分配必需的空间,因此它克服了 vector 容器在保存固定个数数据浪费内存资源的劣势;同时,跟普通数组不同的是,它保存了自己的 size 信息,同时提供了必要的操作函数,可以方便地安全地对数据进行操作,这又使得它弥补了普通数组的劣势。
array 容器同样是一个类模板,只不过它需要两个特化参数,第一个参数表示这个容器可以保存的数据类型,第二个参数表示这个容器可以保存的数据个数。
// 引入定义 array 容器的头文件
#include <array>
using namespace std;
// 定义一个只能保存 12 个 double 类型数据元素的 array 容器
array<double, 12> arrMonths;
// 像使用普通数组一样,使用下标对容器中的数据元素进行赋值,将数据保存到容器中
arrMonths[0] = 15.4;
arrMonths[1] = 17.6;
// ...
arrMonths[11] =19.7;
同样,我们也可以使用迭代器访问 array 容器中的数据:
// 输出 array 容器中的所有数据
for(auto it = arrMonths.begin();
it != arrMonths.end(); ++it )
{
// 使用迭代器访问 array 容器中的数据
cout<<*it<<endl;
}
array 容器除了无法动态地改变它的大小之外,在操作上, array 容器与 vector 容器并无太大区别。
vector 容器的操作函数
例如:push_back()函数
使用 push_back()函数向 vector 容器中添加数据时,它会接受一个跟 vector容器模板参数数据类型相同的数据,然后将其复制为一个新元素并添加到 vector 容器的末尾,也就是将数据“推送( push)”到 vector 容器的“后面(back)”。
#include<iostream>
#include<vector>
using namespace std;
vector<int> vecSalary;
int nSalary;
int main()
{
while(cin>>nSalary)
{
vecSalary.push_back(nSalary);
}
auto it = vecSalary.begin();
vecSalary.insert(it, 2200);
cout<<"the size of the vector is : "<<vecSalary.size()<<endl;
}
访问 vector 容器中的数据
本质上, vector 容器就是一个数组,跟访问数组中的元素相似,我们同样可以使用“[ ]”符号,以元素在容器中的次序作为下标来访问 vector 容器中的数据。
// 将 vecSalary 容器中的第一个数据元素赋值为 3000
vecSalary[0] = 3000;
但是,为了保证访问元素的安全性, vector 容器更多的是使用迭代器或者 at()函数来访问容器中的数据元素。
// 定义索引值变量,用于访问容器中的数据
vector<int>::size_type nIndex = 0; //在这里完全等价于unsigned int nIndex = 0,此处是为了适应不同平台的int;
// 循环遍历 vector 容器
for( auto it = vecSalary.begin();
it != vecSalary.end(); ++it, ++nIndex )
{
// 通过迭代器读取容器中的数据
cout<<"当前工资是: "<<*it<<endl;
// 通过 at()函数修改容器中元素的值
vecSalary.at( nIndex ) += 1000; // 涨工资啦!每个人加 1000 元!
cout<<"涨工资之后是: "<<*it<<endl;
}