3.3标准库类型vector

本文详细介绍C++中的Vector容器,包括定义、初始化、添加元素及常用操作。解释如何使用列表初始化,探讨不同初始化方式的区别,并给出实用示例。


标准vector表示对象的集合,其中所有的对象的类型都相同。集合中的每个对象都有一个与之相对应的索引,索引用于访问对象。因为vector"容纳着"其他的对象,所以它也常常被称作 容器,现在先对其进行简单介绍。

要想使用vector,必须包含其头文件#include<vector>

C++语言既有类模板,也有函数模板,其中vector是一个类模板,只有对于C++有深入的了解才能写出模板。

以vector为例子,提供额外的信息是vector内所存储的对象的类型:

vector<int> ivec;//1
vector<Sales_item> Sales_vec;//2
vector<vector<string>> files;//3

  1. ivec保存的是int类型的对象
  2. Sales_vec保存的是Sales_item的对象
  3. 该向量的元素是vector对象

vector是模板而非类型,由vector生成的类型必须包含vector中元素的类型,如vector<int>

PS:vector可以容纳绝大多数类型的对象作为其元素,但是因为引用不是对象,所以不存在包含的vector。

PS:有些编译器仍然采用老式的用法,在编写以vector为元素的vector容器的时候,需要加一个空格,如:

vector<vecto<vector> > files;

定义和初始化vector对象

与任何一种类型相同,vector模板那控制着定义和初始化向量的方法下面将列出来:

vector<T> v1//1
vector<T> v2 = v1//2
vector<T> v3(n,val)//3
vector<T> v4(n)//4
vector<T> v5{a,b,c…}//5
vector<T> v6 = {a,b,c…}//6

  1. v1是一个空的容器,潜在存储的类型是T类型
  2. v2中包含由v1中所有元素的副本等效于v2(v1)
  3. v3中包含了n个重复的val值
  4. v4中包含了n个默认值(一般为0)
  5. v5中包含了n个元素,分别是a,b,c…
  6. v6等效于v5

还有就是在拷贝容器的时候,也需要注意的是两个容器的类型应当相同

列表初始化vector对象

C++11新标准提供了一个新的列表初始化的方式来进行初始化vector对象
例如:

vector<string> articles = {“a”,“an”,“the”};//1
vector<string> articles = (“a”,“an”,“the”);//2

  1. 正确
  2. 错误

这里介绍一下该初始化的规则:

  1. 使用拷贝初始化的时候,只能提供一个初始值。
  2. 如果提供的是一个类内的初始值,则只能使用拷贝初始化,或者使用花括号的形式进行初始化。
  3. 如果提供的是初始化列表,则只能把初始值都放在花括号里面进行列表初始化,而不能放在圆括号里面。

创建指定数量的元素

vector<T> v3(n,val)
vector<T> v4(n)

见上就行,也没什么分析的。

值初始化

如果vector对象的元素是内置类型,比如int,则元素的初始值自动设为0,如果元素是某种类型,比如string,则元素由该类的默认初始话决定。

vector<T> v4(n)

而对于此种初始化有着两个特殊的限制:

第一:有些类型要求必须明确提供初始值,如果vector对象中元素的类型不支持默认初始化,我们就必须提供初始化的元素值。

第二:如果只提供了元素的数量,而没有设定初始值,只能使用直接初始化

列表初始值还是元素的数量?

某些情况下,初始化的真实含义依赖于传递初始值的是花括号还是圆括号,例如:用一个整数来初始化vector<int >的时候,整数的含义可能是vector对象的容量也可能是元素的值。类似的,用两个整数来初始化vector<int>,这两个整数可能是一个元素初始值。通过使用花括号和圆括号可以区别上述的区别:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	vector<int> v1(10);//1
	vector<int> v2{ 10 };//2

	vector<int> v1(10,1);//3
	vector<int> v1{ 10,1 };//4

	return 0;
}
  1. v1当中有10个元素,都是0。
  2. v2中只有1个元素10。
  3. v3中由10个元素,都是1。
  4. v4中有2个元素,10和1。

这里浅讲一下花括号和圆括号的区别:

如果使用的是圆括号,可以说是在构造vector对象。

如果是在使用花括号,表示我们正在使用列表初始化该vector对象,也就是说初始化过程中,会把花括号当中的数据当作元素进行使用,只有在无法执行初始化列表的时候才会考虑其他的初始化方式。

但在这里还有一个易错点就是,这里的列表初始化仅仅只是优先如果内部的值无法进行初始化,他还是会调用默认初始化的方式进行运行的。

#include<iostream>
#include<string>
#include<cctype>
#include<vector>
using namespace std;

int main()
{
	vector<string> v5{ "hi" };//1
	vector<stirng> v6("hi");//2
	vector<string> v7(10);//3
	vector<string> v8{ 10,"hi" };//4
	return 0;
}
  1. 列表初始化,不介绍
  2. 错误,调用初始化函数错误
  3. 10个空string类型
  4. 虽然是花括号,但这里的运行,改变成了圆括号的使用。

向vector对象中添加元素

对于vector对象来说,直接初始化的方式使用于三种情况:初始值已知且数量较少,初始值是另一个vector对象的副本,所有的元素的初始值都一样。但是常见的情况却是相反的,所以便需要用到一个函数push_back向其中添加元素。push_back负责把一个值当成vector对象的尾元素压入vector的尾端

例如

#include<vector>
using namespace std;

int main()
{
	string word;
	vector<string> text;
	while (cin>>word)
	{
		text.push_back(word);
	}
	cout << "结束" << endl;
	return 0;
}

还有就是建议是:开始的时候创建空的vector对象,在运行的时候再动态添加元素。

向vector对象添加元素蕴含的编程假定

如果循环体内包含着有向vector对象添加元素的语句,则不能使用规范的for循环,具体可以见之后专门for的区域进行分析。

其他的vector操作

除了push_back以外,vector还提供了几种操作,大多数都和string的相关操作类似。

v.empty()//1
v.size()//2
v.push_back(t)//3
v[n]//4
v1=v2//5
v1={a,b,c…}//6
v1==v2//7
v1!=v2//8
<、<=、>、>=//9

  1. 如果v不含有任何元素,则返回true,否则返回false
  2. 返回v中元素的个数
  3. 向v的尾端添加一个为t的元素
  4. 返回v中第n个位置上的元素的引用
  5. 用v2中的元素拷贝替换v1中的元素
  6. 用列表中的元素拷贝替换v1中的元素
  7. v1和v2相等当且仅当他们的元素数量相同且对应位置的元素值都相同
  8. 与上面相反
  9. 顾名思义,按字典顺序比较

访问vector当中的元素与string对象中的字符方法差不多,也是通过元素再vector对象中的位置。
例如:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	vector<int> v1{ 1,2,3,4,5,6,7,8,9 };
	for (auto& i : v1)//这里注意是引用
		i *= i;
	for (auto i : v1)
		cout << i << " ";
	cout << endl;
	return 0;
}

这里有一个比较细节的东西就是需要使用引用类型,如果不使用引用类型,就仅仅只是i=容器中的值,改成引用后才可以修改容器当中的数据。

而对于vector的empty和size两个成员与string的同名成员的功能完全一致,但是在使用对应的size_type的时候也需要指明是谁定义的size_type,比如vector<int>::size_type.而非vector::size_type。

而其他的相同函数也不再赘述,读者可翻阅之前的本专栏的上一篇进行了解

计算vector内对象的索引

使用下标运算符能获取收到指定的元素。和string一样vector的对象下标也是从0开始,下标的类型是size_type类型的,只要vector的对象不是一个常量,就可以向下标运算符返回的元素赋值。简单举个例子:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	vector<unsigned> score(11, 0);
	unsigned grade;
	while (cin>>grade)
	{
		if (grade <= 100)
			++score[grade / 10];
	}
	return 0;
}

统计各分数段的学生个数,大家有兴趣可以调试一下。

不能使用下标的形式添加元素

顾名思义,当你想通过下标的形式添加元素的时候,你就会发现该位置是为空,根本没有对于区域进行添加,这也是新手很容易犯的错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值