vector【1】介绍与使用(超详解哦)

12 篇文章 0 订阅

引言

在string部分,我们详细的介绍了各个接口的使用,虽然其不属于STL的一部分,但是接口与STL中的容器相似,所以我们在学习使用vector等STL容器的使用时,就会简单许多:
戳我康string的使用详解哦

vector介绍

vector是可变大小数组序列容器
vector的底层是一块动态申请连续的空间,与数组类似,vector可以通过下标高效的访问数组中的元素;同时由于是动态申请的空间,可以根据需求扩容,弥补了数组大小固定的缺陷;
但是,在进行插入时,vector会根据需要自动扩容,这个过程中需要重新申请一块空间并拷贝数据,会十分影响效率。所以库中的vector会在申请空间时预先多申请一些空间,并以2倍或1.5倍的扩容规则来以减少拷贝行为的发生
vector尾插与尾删的效率非常高,但是其在任意位置插入与删除时,尤其是头插与头删时,就需要挪动数据,效率相对会低很多。所以vector的接口就直接没有支持push_frontpop_front所以vector更适合多次尾插尾删,并且需要经常随机访问其中元素的数据的存储
vector是一个类模板,可以支持存储任意类型的数据:
在这里插入图片描述

接口使用

与string类似,vector也有默认成员函数、迭代器、容量、元素访问、数据修改等接口(使用库vector时需要包含头文件#include<vector>

默认成员函数

构造
构造函数部分重载有,无参构造、n个指定元素构造、迭代器区间构造以及拷贝构造
在这里插入图片描述
由于vector是一个类模板,所以在使用vector来实例化对象是,就需要显式指定模板参数,如vector<int>

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

int main()
{
	vector<int> v1; //无参初始化
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	vector<int> v2(10, 6);  //使用10个6初始化
	for (auto e : v2)
	{
		cout << e << " ";
	}
	cout << endl;

	vector<int> v3(v2.begin(), v2.end());  //使用迭代器区间初始化
	for (auto e : v3)
	{
		cout << e << " ";
	}
	cout << endl;

	vector<int> v4(v3); //拷贝构造
	for (auto e : v4)
	{
		cout << e << " ";
	}
	cout << endl;
}

在这里插入图片描述

析构
析构函数在该对象生命周期结束时由编译器自动调用
在这里插入图片描述
赋值重载
在这里插入图片描述
v2赋值给v1

int main()
{
	vector<int> v1;
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	vector<int> v2(10, 6);
	for (auto e : v2)
	{
		cout << e << " ";
	}
	cout << endl;

	v1 = v2;
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
}

在这里插入图片描述

迭代器

在这里插入图片描述
vector的迭代器用法与string相同,并且他们的底层都是原生指针。我们可以使用迭代器访问容器中的元素,也可以使用范围for遍历容器中的元素。
begin返回首元素位置的迭代器,end返回尾元素下一个位置的迭代器、rbegin返回尾元素的反向迭代器、rend返回首元素前一个位置的反向迭代器。后面的cbegincendcrbegincrend都是返回其对应的const迭代器,但是前面的函数都有重载const版本。

int main()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	v1.push_back(6);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
	cout << *v1.begin() << endl;
	cout << *(v1.end() - 1) << endl;
	cout << *v1.rbegin() << endl;
	cout << *(v1.rend() - 1) << endl;

	return 0;
}

在这里插入图片描述

容量

在这里插入图片描述
与string类似,size返回容器中元素的个数;resize用于修改容器中元素的个数;capacity返回容器的容量;empty判断容器是否为空;reserve用于修改容器的容量(关于C++11新增的接口先暂时不做介绍):

int main()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	v1.push_back(6);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << "size:" << v1.size() << " ";
	cout << "capacity:" << v1.capacity() << " ";
	cout << endl;

	v1.reserve(25);//使用reserve修改容量
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << "size:" << v1.size() << " ";
	cout << "capacity:" << v1.capacity() << " ";
	cout << endl;

	v1.resize(3);//使用resize修改数据数量
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << "size:" << v1.size() << " ";
	cout << "capacity:" << v1.capacity() << " ";
	cout << endl;

	v1.resize(10, 6);//使用reserve增大数据数量,并使用6补足
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << "size:" << v1.size() << " ";
	cout << "capacity:" << v1.capacity() << " ";
	cout << endl;
	return 0;
}

在这里插入图片描述

元素访问

在这里插入图片描述
operator[]at都可以通过下标访问对应位置的元素,不同的是:operator[]当传递的下标越界时,就会崩溃并直接终止程序;当at传递的下标越界时,会抛异常,可以被try-catch捕获,而不会导致程序终止
front会返回首元素的引用、back会返回尾元素的引用。

正常访问:

//正常访问时
int main()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	v1.push_back(6);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	cout << v1[3] << endl;
	cout << v1.at(3) << endl;
	cout << v1.front() << endl;
	cout << v1.back() << endl;

	return 0;
}

在这里插入图片描述
越界访问:

//越界访问
int main()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	v1.push_back(6);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	//at越界访问
	try
	{
		cout << v1.at(6) << endl;
	}
	catch(const exception& e)
	{
		cout << e.what() << endl;
	}
	cout << "访问继续" << endl;
	//operator[]越界访问
	try
	{
		cout << v1[6] << endl;
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}
	cout << "访问继续" << endl;

	return 0;
}

在这里插入图片描述

数据修改

在这里插入图片描述
对于数据修改,与string类似:
push_back用于在序列尾插入一个元素;
pop_back用于在序列尾删除一个元素(由于vector中头插与头删的效率过低,所以不提供接口):

int main()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	v1.push_back(6);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	v1.pop_back();
	v1.pop_back();
	v1.pop_back();
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

在这里插入图片描述

insert用于在序列中的任一位置(迭代器)插入一个元素、n个指定元素或一段迭代器区间中的元素;
在这里插入图片描述

int main()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	v1.push_back(6);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	vector<int> v2;
	v2.insert(v2.begin(), 6); //相当于头插6
	v2.insert(v2.end(), 7);  //相当于尾插7
	for (auto e : v2)
	{
		cout << e << " ";
	}
	cout << endl;

	v2.insert(v2.end(), 5, 0);  //尾插5个0
	for (auto e : v2)
	{
		cout << e << " ";
	}
	cout << endl;

	v2.insert(v2.end(), v1.begin(), v1.end());  //尾插一个v1
	for (auto e : v2)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

在这里插入图片描述

erase用于在序列的任一位置删除一个元素,或删除一段迭代器区间中的元素;
在这里插入图片描述

int main()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	v1.push_back(6);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	v1.erase(v1.begin() + 1); //删除第二个元素
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
	
	v1.erase(v1.begin() + 1, v1.end() - 1); //删除一个迭代器区间
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
	
	return 0;
}

在这里插入图片描述

swap用于交换两个vector中的数据;
clear用于清理vector中的数据(不改变容量):

int main()
{
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	v1.push_back(5);
	v1.push_back(6);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;

	vector<int> v2(6, 6);
	for (auto e : v2)
	{
		cout << e << " ";
	}
	cout << endl;

	//交换两个vector的数据
	v1.swap(v2);
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
	for (auto e : v2)
	{
		cout << e << " ";
	}
	cout << endl;

	//清除两个vector中的数据
	v1.clear();
	v2.clear();
	for (auto e : v1)
	{
		cout << e << " ";
	}
	cout << endl;
	for (auto e : v2)
	{
		cout << e << " ";
	}
	cout << endl;

	return 0;
}

在这里插入图片描述

迭代器失效问题

我们在使用容器时,常需要通过迭代器来访问元素,他起着指针的作用,本质上也就是原生指针或是指针的封装。我们在使用指针时,如果处理不当,就会遇到访问野指针的错误。对于迭代器也存在着这样的问题,即迭代器失效
在容器中,对其底层空间的改变通常会导致迭代器失效,例如一些vector接口就有可能会改变其底层的空间:resizereserveinsertassignpush_back等这些接口都可能会发生扩容而释放原空间,从而使指向原空间的一些指针成为野指针而发生迭代器失效(后面模拟实现后会对此有更好的理解)。访问失效的迭代器,即访问野指针,会导致程序崩溃:

int main()
{
	vector<int> v1(6, 6);
	vector<int>::iterator it = v1.begin() + 1; //指向第二个元素

	v1.reserve(100); //使用reserve将其扩容至100,会发生底层空间的替换
	cout << *it << endl; //再次访问这个迭代器就会导致程序崩溃
	return 0;
}

在这里插入图片描述
所以在使用有可能发生扩容的接口后,就不能再使用之前的迭代器了。

另外,erasepop_back等接口虽然不会替换容器的底层空间,但是可能会使原来的迭代器的指向发生改变,当指向一块未定义的位置时,也会发生失效

总结

到此,关于vector的介绍以及接口的使用就介绍完了
STL的容器接口在使用时都有很多相似之处,在后面了解到更多的容器后就会体会到

如果大家认为我对某一部分没有介绍清楚或者某一部分出了问题,欢迎大家在评论区提出

如果本文对你有帮助,希望一键三连哦

希望与大家共同进步哦

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿qiu不熬夜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值