vector
类型表示对象的集合,所有对象的类型都相同。
集合中的每个对象都有一个与之对应的索引,用于访问对象。
vector
容纳着其他对象,也被称作容器。
使用vector
必须包含适当的头文件。
#include <vector>
using std::vector
vector
是一个类模板,模板不是类或函数。编译器根据模板创建类或函数的过程成为实例化,当使用模板时,需要指出把类和函数实例化成何种类型。
类模板需要提供一些额外的信息指定模板实例化为什么样的类,提供哪些信息由模板决定,模板名字后跟一对尖括号,括号内放上信息。
vector
为例:
vector<int>ivec; // ivec保存int类型的对象
vector<Sales item>Sales_vec; // 保存Sales_item类型的对象
vector<vector<string>> file; // 该向量的元素是vector对象
vector
能容纳绝大多数类型的对象作为其元素,引用不是对象,不存在包含引用的vector
。大多数内置类型和类都可以构成vector
,也可以是vector<vector<>>
。
定义和初始化vector
对象
vector
对象初始化的方法:
vector<T> v1 // v1是一个空vector,它潜在的元素是T类型的,执行默认初始化
vector<T> v2(v1) // v2中包含有v1所有元素的副本
vector<T> v2 = v1 // 等价于v2(v1),v2中包含有v1所有元素的副本
vector<T> v3(n,val) // v3包含了n个重复的元素,每个元素的值都是val
vector<T> v4(n) // v4包含了n个重复地执行了值初始化的对象
vector<T> v5{a,b,c...} // v5包含了初始值个数的元素,每个元素被赋予相应的初始值
vector<T> v5 = {a,b,c...} // 等价于v5{a,b,c...}
- 可以默认初始化
vector
对象,创建一个空vector
- 最常见的方式是先定义一个空
vector
,运行时获取到元素的值后再逐一添加。 - 定义
vector
对象时指定元素的初始值,允许把一个vector
对象的元素拷贝给另一个vector
对象。新的vector
对象的元素是原vector
对应元素的副本。两个vector
对象的类型必须相同。
列表初始化vector
对象
列表初始化:用花括号括起来的0个或多个初始元素被赋给vector
对象。
C++几种不同的初始化方式,大多情况可以等价使用,除了:
- 使用拷贝初始化时,只能提供一个初始值
- 若提供的是类内初始值,只能使用拷贝初始化或花括号的形式初始化
- 若提供的是初始元素值的列表,只能把初始值都放在花括号里进行列表初始化,不能放在圆括号里。
vector<string> vl{"a", "an", "the"}; //列表初始化
vector<string> v2("a", "an", "the"); //错误
创建指定数量的元素
用vector
对象容纳的元素数量和所有元素的统一初始值来初始化vector
对象。vector<int> ivec{10, -1}; // 10个int类型的元素,每个都被初始化为-1
值初始化
可以只提供vector
对象容纳的元素数量而不用略去初始值,此时库会创建一个值初始化元素初值,并把它赋给容器中的所有元素,初值由vector
对象中的元素的类型决定。
- 如果
vector
对象的元素是内置类型,int
:初始值自动设为0 - 如果元素是某种类,元素由类默认初始化,
string
:设置为空串
两个特殊限制 - 有些类明确要求提供初始值
- 若只提供了元素的数量而没有设定初始值,只能使用直接初始化(不用
=
)
列表初始值/元素数量
某些情况下,初始值的真实含义依赖于传递初始值时用的是花括号还是圆括号:
vector<int> v1(10); // v1有10个元素,每个的值都是0
vector<int> v2{10}; // v2有1个元素,该元素的值是10
vector<int> v3(10, 1); // v3有10个元素,每个的值都是1
vector<int> v4{10, 1}; // v4有2个元素,值分别是10和1
- 如果用的是圆括号,称提供的值是用来构造
vector
对象的。 - 如果用的是花括号,表述为我们想列表初始化该
vector
对象。 - 如果初始化时使用了花括号但提供的值又不能用来列表初始化,就考虑用这样的值来构造
vector
对象了。
vector<string> v5{"hi"}; // 列表初始化:v5有一个元素
vector<string> v6("hi"); // 错误:不能使用字符串字面值构建vector对象
vector<string> v7{10}; // v7有10个默认初始化的元素
vector<string> v8{10, "hi"}; // v7有10个默认初始化的元素
要执行列表初始化vector
对象,花括号的值必须与元素类型相同;确认无法执行列表初始化后,编译器尝试使用默认初始化vector
对象。
vector<int> v1; // 空
vector<int> v2(10); // 10个0
vector<int> v3(10, 42); // 10个42
vector<int> v4{10}; // 1个10
vector<int> v5{10, 42}; // 2个元素 10,42
vector<string> v6{10}; // 10个空串
vector<string> v7{10, "hi"}; // 10个“hi”
向vector
对象中添加元素
对于vector
对象,直接初始化的方式适用于三种情况:
- 初始值已知且数量较少
- 初始值是另一个
vector
对象的副本 - 所有元素的初始值都一样
更多的情况是:创建一个vector
对象并不清楚实际的元素个数和元素的值;有些时候元素的初值已知,但这些值总量大且各不相同。
创建一个空vector
,运行时再利用vector
的成员函数push_back
向其中添加元素。push_back
负责把一个值当成vector
对象的尾元素push到vector
对象的尾端。
vector<int> v2; //空vector对象
for (int i = 0; i != 100; ++i)
v2.push back(i);//依次把整数值放到v2尾端
string word; vector<string> text; //空 vector对象
while(cin>>word){
text.push back(word); // 把word添加到text后面
}
vector
对象能高效增长,元素的值有所不同,更有效的办法是定义一个空的vector
,运行时向其添加具体的值。
向vector
对象添加元素蕴含的编程假定
必须确保所写的循环正确无误,特别是在循环有可能改变vector
对象容量的时候。
如果循环内部包含向vector
对象添加元素的语句,则不能使用范围for
循环。
- 范围
for
语句体内不应改变其所遍历序列的大小。
其他vector
操作
vector
支持的操作
v.empty() // 如果v不含有任何元素,返回真;否则返回假
v.size() // 返回v中元素的个数
v.push_back(t) // 向v的尾端添加一个值为t的元素
v[n] // 返回v中第n个位置上元素的引用
v1 = v2 // 用v2中元素的拷贝替换v1中的元素
v1 = {a,b,c...} // 用列表中元素的拷贝替换v1中的元素
v1 == v2 // v1和v2相等当且仅当它们的元素数量相同且对应位置的元素值都相同
v1 != v2
<,<=,>,>= // 顾名思义,以字典顺序进行比较
使用范围for
语句处理对象vector
中的所有元素
vector<int> v;
for (auto &i : v)
for (auto i : v)
vector
的empty
和size
两个成员与string
同名成员的功能完全一致。
- 使用
size_type
,需要首先指它是由哪种类型定义的。vector
对象的类型总是包含着元素的类型。
vector<int>::size type // 正确
vector::size type // 错误
各个相等性运算符和关系运算符也与string
的相应运算符功能一致。
- 两个
vector
对象相等当且仅当它们所含的元素个数相同,而且对应位置的元素值也相同。
关系运算符依照字典顺序进行比较: - 如果两个
vector
对象的容量不同,但在相同位置上的元素值都一样,则元素较少的vector
对象小于元素较多的vector
对象; - 若元素的值有区别,则
vector
对象的大小关系由第一对相异的元素值的大小关系决定。
只有当元素的值可比较时,vector
对象才能被比较。
计算vector
内对象的索引
使用下标运算符能获取到指定的元素。
vector
对象的下标也是从0开始,下标的类型是相应的size_type
类型。- 只要
vector
对象不是一个常量,就能向下标运算符返回的元素赋值。 - 可以计算得到对象的索引,直接获取索引位置上的元素。
- 使用下标的时候必须清楚地知道它是否在合理的范围内。
不能用下标形式添加元素
vector<int> ivec; // 空vector对象
for (decltype(ivec.size()) ix = 0; ix != 10; ++ix)
ivec[ix] = ix; // 严重错误:ivec不包含任何元素
ivec
是一个空的vector
,根本不包含任何元素,也不能通过下标去访问任何元素。
for (decltype(ivec.size()) ix = 0; ix != 10; ++ix)
ivec.push back(ix); // 正确:添加一个新元素,该元素的值是ix
vector
对象(以及string
)对象的下标运算符访问已存在的元素而不能用于添加元素。
只能读确知已存在的元素执行下标操作。