vector基础(1)

前言

前几节我们学习了string类,那么本节我们来学习一下vector类,vector正式属于STL的一员。有了string类的学习基础,vector类的学习会更加容易上手一些,那么废话不多说,我们正式进入今天的学习

使用vector我们需要包含头文件<vector>

vector是一个标准的模板,第一个模板参数表示要存放的数据类型;第二个参数的类型是一个空间配置器和内存池,可以提高内存使用的效率。目前我们不需要管,不需要去传参


1.vector的构造、析构、赋值

vector的英文意思是向量,但vector的本质其实是一个可以进行扩容的顺序表。vector的接口设计得非常简洁,不像string类那么的冗余,那么我们还是首先来看一下vector的构造

(这里需要注意:allocator是空间配置器,我们暂时不需要管)

(1):这里表示的是一个无参数的构造

(2):这里表示使用n个value的值去完成构造

(3):这里表示用迭代器区间完成构造

(4):这里表示的是拷贝构造

void test_vector1()
{
	vector<int> v1;
	vector<int> v2(3, 6);
	vector<int> v3(++v2.begin(), v2.end());
	vector<int> v4(v3);
}


下面我们来看一下vector的析构

vector的析构函数也是直接自动调用的,这里不做过多讲解了


我们最后来看一下vector的赋值:

这一块也没什么好说的,就是用一个vector赋值给另外一个vector


假设我们在这里想要遍历一下vector该怎么办呢?

和之前学习string一样,我们有三种方式来遍历vector:

1.下标+[] 遍历

	vector<int> v1;
	vector<int> v2(3, 6);
	vector<int> v3(++v2.begin(), v2.end());
	vector<int> v4(v3);
	for (size_t i = 0; i < v2.size(); i++)
	{
		cout << v2[i] << " ";
	}

2.使用迭代器遍历

这里可以用正向迭代器、反向迭代器、const迭代器等来遍历,不一一演示了,这里只选取正向迭代器为例子进行讲解:

因为迭代器都是定义在类域中的,所以在使用迭代器的时候需要指定类域:

	while (it != v2.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

3.使用范围for遍历

范围for的底层就是使用的迭代器,所以也没有什么好说的:

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


2.vector中与容量有关的接口

vector中与容量有关的接口如下所示:


1.size

该接口可以返回vector中存在的元素的个数

void test_vector2()
{
	vector<int> v1(3,6);
	cout << v1.size() << endl;
}

2.max_size

该接口可以返回vector最大可以存放的元素个数(演示代码为32位下的情况)

	vector<int> v1(3,6);
	cout << v1.max_size() << endl;


3.resize

该接口可以调整vector容量的大小

参数n的意思是:调整容器的大小,使其包含 n 个元素

如果 n 小于当前容器大小(size),则内容将减少到其前 n 个元素,删除超出此部分的元素

如果 n 大于当前容器大小(size),则通过在末尾插入所需数量的元素来扩展内容,以达到 n 的大小。如果指定了 val ,则新元素将初始化为 val 的副本,否则,它们将进行值初始化

如果 n 同时大于当前容器容量(capacity),则会自动重新分配空间

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

                                              


4.capacity

该接口可以返回当前为 vector 分配的存储空间的大小

capacity不一定等于size,,它可以相等或更大

当capacity耗尽并需要更多容量时,vector会自动扩展(重新分配存储空间)

	vector<int> v1(3, 6);
	cout << v1.size() << endl;
	cout << v1.capacity() << endl;
	v1.resize(4);
	cout << v1.size() << endl;
	cout << v1.capacity() << endl;

                                                  


5.empty

该接口可以判断容器是否为空,如果为空,则返回true,否则返回false

	vector<int> v1;
	vector<int> v2(3, 6);
	cout << v1.empty() << endl;
	cout << v2.empty() << endl;

                        ​​​​​​​        ​​​​​​​           


6.reserve

该接口可以自行改变容量的大小(capacity)

在学习reserve之前我们先来看一下编译器自动扩容的规则

void TestVectorExpand()
{
	size_t sz;
	vector<int> v;
	sz = v.capacity();
	cout << "capacity changed: " << sz << '\n';
	cout << "making v grow:\n";
	for (size_t i = 0; i < 100; i++)
	{
		v.push_back(i);
		if (sz != v.capacity())
		{
			sz = v.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}

        

我们看数据可以知道自动扩容是1.5倍扩容,并且做了向上取整

**************************************************************************************************************

g++环境下是两倍扩容:

**************************************************************************************************************

我们接着来看看reserve的定义:

reserve接口可以请求一个足够的且最少的空间,这也就意味着当我们给出n大小,真实开辟空间的大小不一定是n,但是开辟空间的大小一定能够容纳下n个数据

如果我们知道了要扩容的大小的话,我们就可以直接用reserve,这样接可以减少扩容的次数,提高程序运行的效率:

	size_t sz;
	vector<int> v;
	v.reserve(100);
	sz = v.capacity();
	cout << "capacity changed: " << sz << '\n';
	cout << "making v grow:\n";
	for (size_t i = 0; i < 100; i++)
	{
		v.push_back(i);
		if (sz != v.capacity())
		{
			sz = v.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}

我们将vector中的reserve和string中的reserve比较一下:

通过比较我们可以发现:string中的reserve在特殊的情况下会有不具有约束力的缩容的现象(具体情况取决于代码实现的过程),但是缩容绝对不会删除已经存在的数据。也就是说如果存在缩容的现象,那么缩容最多缩到size的大小

而vector中的reserve不会存在缩容的现象

我们来验证一下:

void test_vector3()
{
	vector<int> v(10, 1);
	v.reserve(20);
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	v.reserve(15);
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	v.reserve(5);
	cout << v.size() << endl;
	cout << v.capacity() << endl;
}

可以看到没有存在缩容的现象

**************************************************************************************************************

GCC下也不会缩容

**************************************************************************************************************

7.shrink_to_fit函数

该接口可以减少capacity的大小,让其大小去适应size的大小

需要注意的是,该接口的请求不是固定的,由编译器实现自由优化

	vector<int> v(10, 1);
	v.reserve(20);
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	v.shrink_to_fit();
	cout << v.size() << endl;
	cout << v.capacity() << endl;


3.vector中与修改有关的接口

vector中与修改有关的接口如下所示:

1.assign

该接口可以为vector指定新的内容,同时删除之前已经存在的数据

	vector<int> v(3, 6);
	v.assign(6, 8);
	for (auto ch : v)
	{
		cout << ch << " ";
	}


2.push_back和pop_back

这个接口就很常规了,就是尾插和尾删,就不做过多的解释了

注意:vector不支持头插和头删,而string是支持的


3.insert

该接口可以实现在指定位置插入数据。需要注意vector中的insert不支持下标访问了,只支持迭代器访问

	vector<int> v(10,1);
	v.insert(v.begin(), 0);
	for (auto ch : v)
	{
		cout << ch << " ";
	}
	cout << endl;
	v.insert(v.begin() + 1, 6);
	for (auto ch : v)
	{
		cout << ch << " ";
	}
	cout << endl;

注意:我们要尽量减少使用insert和erase,因为每次使用都需要移动数据,这会大大降低程序的运行效率


4.erase

该接口可以实现删除指定位置的数据。该接口的使用方式和insert差不多,就不做过多的解释了


5.swap

该接口可以实现交换数据的功能,也无须多言


6.clear

该接口可以删除vector中的所有数据将size改为0但是clear不会改变capacity

	vector<int> v(3, 6);
	cout << v.size() << endl;
	cout << v.capacity() << endl;
	v.clear();
	cout << v.size() << endl;
	cout << v.capacity() << endl;


emplace系列暂时不需要管,后面才会学习到,它的功能和insert类似


我们需要注意:vector是不支持流插入和流提取的

string中支持流插入和流提取的原因是它是比较固定的,字符都是一个接一个的打印,直到遇到

\0才中止。

而vector的情况就比较特殊,所以不支持。我们要在vector中插入一个数据其实也很简单:

	vector<int> v(3, 6);
	v.clear();
	int x;
	cin >> x;
	v.push_back(x);

输入多个数据也很简单:

	vector<int> v(10, 0);
	for (size_t i = 0; i < 10; i++)
	{
		cin >> v[i];
	}

我们再来思考一下 vector<char> v 能否替代 string s 呢?

答案是不能的,string后面会有\0,而vector后面是没有\0的。因为string里面包含\0,它就能够很好的兼容C语言

vector中加\0是不能的,因为vector的类型不止有char,各个类型中的\0含义是不一样的

而且只有字符能实现连贯的赋值和初始化,如"abcdefg";而整型连贯赋值就会导致含义不明了,假设我们要给五个变量1,2,3,4,5,连续输入结果为:"12345"。此时就会混淆


结尾

那么有关vector使用的基础内容到此就差不多结束了,更多的细节可以去官网查阅vector的文档。希望该文章可以给你带来帮助,谢谢您的浏览!!!

  • 29
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值