STL(StandardTemplateLibrary),即标准模板库,是一个具有工业强度的,高效的C++程序库。它拥有六大组件,分别为容器(Container),迭代器(Iterator),算法(Algorithm),仿函数(Function object),迭代适配器(Adaptor),空间配制器(allocator)。本篇文章带你走进STL中使用最为广泛的一个容器——vector,通过这篇文章,你将了解到vector基本的内部构造以及使用方法。
顾名思义,vector意为向量,可以存储一维数组,二维数组和多维数组,但是它又比数组更优越,数组不能动态扩展,因此在程序运行的时候不是浪费内存,就是造成越界。而vector正好弥补了这个缺陷,vector可以动态扩展,同时也像数组一样通过下标访问。vector上常见操作复杂度如下:
· 随机访问——常数O(1)
· 在末尾插入或移除元素——均摊常数O(1)
· 插入或移除元素——与到vector结尾的距离成线性O(n)
下面我们先介绍一下vector的使用方法,使用vector首先需要添加其头文件,其头文件名也是vector,同时需要传入一个模板参数,参数必须是完整类型并满足可擦除(Erasable)的要求,即接受有可访问析构函数的类类型和所有标量类型,但拒绝数组类型、函数类型、引用类型和void。
初始化
std::vector<int>v1; //vector元素为int型,无初始值
std::vector<string>v2; //vector元素为string型,无初始值
std::vector<int>v3={1,2,3,4}; //vector元素为int类型,且包含四个整数1,2,3,4
std::vector<int>v4(3,100); //vector元素为int类型,包含三个整数100,100,100
添加元素
在C++11之前,添加元素一般用push_back和insert函数
std::vector<int>numbers;
// push_back
numbers.push_back(15);
numbers.push_back(16);
std::cout<<"插入到vector末尾,vector元素排列为:";
for(inti:numbers)
std::cout<<i<<"";
std::cout<<std::endl;
//输出:插入到vector末尾,vector元素排列为:15 16
// insert
numbers.insert(numbers.begin(),14);
std::cout<<"插入到vector首位,vector元素排列为:";
for(inti:numbers)
std::cout<<i<<"";
std::cout<<std::endl;
//输出:插入到vector首位,vector元素排列为:14 15 16
从C++11起,vector允许我们在容器末尾就地构造元素,,这样可以避免用push_back时的额外复制或移动操作,如下所示(此示例代码来自C++官方文档)
#include <vector>
#include <string>
#include <iostream>
structPresident
{
std::stringname;
std::stringcountry;
intyear;
President(std::stringp_name,std::stringp_country,intp_year)
:name(std::move(p_name)),country(std::move(p_country)),year(p_year)
{
std::cout<<"I am being constructed.\n";
}
President(President&&other)
:name(std::move(other.name)),country(std::move(other.country)),year(other.year)
{
std::cout<<"I am being moved.\n";
}
President&operator=(constPresident&other)=default;
};
intmain()
{
std::vector<President>elections;
std::cout<<"emplace_back:\n";
elections.emplace_back("Nelson Mandela","South Africa",1994);
std::vector<President>reElections;
std::cout<<"\npush_back:\n";
reElections.push_back(President("Franklin Delano Roosevelt","the USA",1936));
std::cout<<"\nContents:\n";
for(Presidentconst&president:elections) {
std::cout<<president.name<<" was elected president of "
<<president.country<<"in "<<president.year<<".\n";
}
for(Presidentconst&president:reElections) {
std::cout<<president.name<<" was re-elected president of "
<<president.country<<"in "<<president.year<<".\n";
}
}
//输出:
emplace_back:
Iambeingconstructed.
push_back:
Iambeingconstructed.
Iambeingmoved.
Contents:
NelsonMandelawaselectedpresidentofSouthAfricain1994.
FranklinDelanoRooseveltwasre-electedpresidentoftheUSAin1936.
删除元素
删除元素包括删除末尾元素和删除指定元素
//初始化一个含有五个int型(1,2,3,4,5)的vector容器
std::vector<int>numbers={1,2,3,4,5};
// pop_back
numbers.pop_back();
numbers.pop_back();
std::cout<<"删除vector末尾一个元素,vector元素排列为:";
for(inti:numbers)
std::cout<<i<<"";
std::cout<<std::endl;
//输出:删除vector末尾一个元素,vector元素排列为:1 2 3
// erase
numbers.erase(numbers.begin()); //删除开始第一个元素
std::cout<<"删除vector开始一个元素,vector元素排列为:";
for(inti:numbers)
std::cout<<i<<"";
std::cout<<std::endl;
//输出:删除vector开始一个元素,vector元素排列为:2 3
其他
std::vector<int>numbers;
//查看是否为空
std::cout<<numbers.empty()<<std::endl;
//清除内容
numbers.clear();
//查看容纳的元素数
std::cout<<numbers.size()<<std::endl;
//查看可容纳的最大元素数
std::cout<<numbers.max_size()<<std::endl;
//查看当前存储空间能够容纳的元素数
std::cout<<numbers.capacity()<<std::endl;
介绍完vector基本的使用方法之后,我们来分析一下vector内部是怎样工作的,下图是vector<T>的内存映像
_first指针指向vector的首元素,_last指向末尾元素,_end指向vector构造出的预留空间的末尾,vector里面有2个成员函数size()和capacity(),capacity()返回vector当前实际空间大小,这部分空间一部分存储元素,另一部分作为预留空间。而size()返回的是当前对象所包含的元素个数。显然,capacity是大于等于size的,当size和capacity相等时,如果继续添加元素,vector就会扩容。一般情况下扩展之后容量等于扩展之前容量的两倍(在VS上运行则是1.5倍),下面我们以一个程序来看一下扩展操作
std::vector<int>vec={1,2,3,4};
std::cout<<"扩展前:"<<std::endl;
std::cout<<"元素个数:"<<vec.size()<<std::endl;
std::cout<<"当前容量:"<<vec.capacity()<<std::endl;
//扩展前:
//元素个数:4
//当前容量:4
vec.push_back(5);
std::cout<<"\n扩展后:"<<std::endl;
std::cout<<"元素个数:"<<vec.size()<<std::endl;
std::cout<<"当前容量:"<<vec.capacity()<<std::endl;
//扩展后:
//元素个数:5
//当前容量:8
作为动态数组,vector有一个指针指向一片连续的内存空间。但是,这个内存空间肯定不是无限大的,当现有容量装不下所有数据时,系统会自动申请一片更大的空间,把原来的数据拷贝过去,释放原来的内存空间。最大可以容纳的元素个数可以通过函数max_size()得到。
更多关于vector请访问C++官方文档之vector