关注

C嘎嘎探索篇:认识vector容器

C嘎嘎探索篇:认识vector容器

前言:

上篇文章小编讲述了string类的模拟实现,小编在刚开始写string类的时候说过,string并不算一个STL容器,只不过它和容器很类似用起来,下面小编将要讲述严格意义上来说我们学的STL的第一个容器:vector容器;下面废话不多说,开始走进vector容器的世界。

正文:

1.vector的介绍

1.1.vector是什么

vector实际上和小编之前写过的顺序表是很类似的,我们可以把vector看成一个顺序表,不过vector可以接纳不同类型的变量,就比如vector可以分为储存int类型数据的vector、储存double类型数据的vector,甚至vector还可以储存string之类的自定义类型,可谓是非常的全面,可能很多读者朋友看到我写vector可以储存这么多类型的变量时,便隐约猜出vector实际上是一个模版类,没错,正如各位猜测的这样,vector类实际上就是一个模版类,这里小编就要多说几句,以后小编讲到的list容器,queue容器等等一系列容器,他们其实都是类模版,模版就意味着他们允许接纳很多类型,这更符合了泛型编程,所以说这便是容器的强大之处,下面小编简单介绍一下vector的一些函数,然后小编在去讲应用。

1.2.vector功能简介

对于我们如何去了解vector可以实现的一些功能,通过一个网站我们便可以知道容器一些功能的使用,这个网站小编推荐过很多次,下面小编放上链接:vector - C++ Reference (cplusplus.com),并且小编截图给读者朋友看一下这个网站。
在这里插入图片描述
通过对这个图片的观察,我们可以快速了解到vector确实是一个模板类,对于这个网站,小编不建议读者朋友去直接机翻这些英文,用过机翻的朋友都知道,有时候机翻翻出来的东西很垃圾,小编觉着于其相信机翻,不如相信自己的英文水平,英文不好的话大不了翻字典一个一个的翻译,这样还会提高自己的英文水平,为以后的读文档做出充足的准备,这句话我可能在以前的文章也说过,但是考虑很多读者朋友是新来的,所以我在这里在叨叨一遍,读者朋友不要嫌烦,毕竟还有很多是新来的读者朋友,想要了解vector的一些功能的话可以在这个网站进行查询,小编就不一一截图占据文章大部分空间了,下面小编将会讲述vector一些功能的使用。

2.vector的使用

2.1.vector的构造函数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如上图所示,vector的构造函数有很多的重载,小编就讲述其中几个比较重要的来说,当然学有余力的读者朋友可以都把这几个构造函数都使用一遍,还是要提前说一下,小编本文讲的vector的接口是不全的,我只是挑重点进行讲述,各位读者朋友最好在看完我文章的基础上,再去探索别的接口的用法,废话不多说,开始进入几个重点构造函数的使用。

**(constructor)**构造函数声明接口说明
vector()(重点)无参构造
vector(size_type n, const value_type& val =value_type())构造并初始化n个val
vector (const vector& x); (重点)拷贝构造
vector (InputIterator first, InputIterator last);使用迭代器进行初始化构
vector(initializer_list x)支持隐式类型转换
2.1.1.vector()

这个接口是一个无参的构造函数,它的使用方法也是很简单,我们仅需在对象的实例化中什么也不写即可,当然,对象的实例化也是一个比较容易错的点,错就错在类类型上,小编在文章开始的时候说过,vector是一个类模版,小编在模版那一节的时候也强调过,类模版对象的实例化是显示实例化,我们要用<>来确定类模版的里面成员的类型,下面小编就展示一下无参构造的实例化:

std :: vector<int> s1;  //这就是显示实例化后的无参构造函数,当我们去进行调试操作的时候,便可以知道此时的s1默认初始化成nullptr了。
2.1.2.vector(size_t type n,const value_type& val = value_type())

这个接口的形参看着十分的复杂,其实它用起来是很简单的,它的功能其实就是构造并且初始化n个val罢了,它的形参之所以这么复杂主要的原因是vector是一个模版类,自然而然函数的形参多多少少和模版参量有关,下面小编展示一下这个函数的用法:

std :: vector<int> s1(10,1);

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.1.3.vector(const vector& x)

这个函数看过前面类和对象文章的读者朋友应该会很熟悉,这个函数的写法就是典型的拷贝构造函数的写法,所以这个构造函数就是一个拷贝构造函数,就是把x拷贝构造给我们要实例化的对象,由于拷贝构造函数是一个比较常见的函数,小编也不废话多说,直接给读者朋友看一下这个代码如何写:

std :: vector<int> s1(10,1);
std :: vector<int> s2 = s1;  //也可以写成,std :: vector<int> s2(s1),小编比较推荐刚开始的写法,因为比较容易理解。
2.1.4.vector(Inputlterator first,Inputlterator last)

这个函数看起来也是一个比较复杂的函数,但是有小编在,包不让各位头疼的,它其实是用迭代器进行初始化构造,也就是说这个函数初始化是通过给上一段某个对象的迭代器区间来进行初始化,小编认为这个和拷贝构造函数是很像的,如果给上一个完整的迭代器区间的话就很像拷贝构造函数了,只不过它们的底层是不太一样的,这个小编会在后面的模拟实现展现出来,下面小编展示这个函数的用法:

std :: vector<int> s1(10,1);
std :: vector<int> s2(s1.begin(),s1.end());  //迭代器相关函数vector和string类是很相似的,当然容器的迭代器函数都死相似的
2.1.5.vector(initializer_list x)

其实除了上面图片的构造函数除外,还有一个类似构造函数的构造函数没有被提及,这个函数可能很多读者朋友看了会很疑惑,这个函数的功能是干啥的?小编也不卖关子了,这个函数实际上是为了支持隐式类型转换而生的,也就是说我们如果想要实现隐式类型转换就必须用这个函数,下面小编展示一下这个函数的使用(PS :这个函数不一定是这么写,我模拟实现是这么做的,只不过肯定是有类似的函数):

std :: vector<int> s1 = {1,2,3,4}; //这里其实是右边的一系列树先转换成vector<int>类型后再通过拷贝构造函数拷贝给s1的,这里就进行了一步隐式类型转换。

以上便就是vector构造函数的写法,各位读者朋友要好好掌握它们的用法,下面我们进入迭代器的使用~

2.2.vector iterator的使用

迭代器相比各位读者朋友都不陌生了,在string类的讲解中小编就讲述了迭代器是什么,感兴趣的读者朋友可以看一下(这里我就不放链接了,因为小编在写这一篇博客的时候string类还没有发布),考虑还有许多读者朋友不知道,小编就简单的说一下迭代器,迭代器就是一个类似指针的东西,有的时候它可以是一个指针(比如我在模拟实现的时候),有的时候它不是一个指针,但是它的用法就是指针的用法,我们可以用迭代器来进行遍历vector容器内容,下面小编就介绍一下迭代器相关的函数。

iterator的使用接口说明
begin + end(重点)获取第一个数据位置的iterator/const_iterator,获取最后一个数据的下一个位置的iterator/const_iterator
rebegin + rend(重点)获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置的reverse_iterator
范围for(重点)可以很快遍历完一个vector容器,以迭代器作为底层实现的,灰常的好用
2.2.1.begin + end

首先登场的就是开头和结尾,这两个函数的功能和它们的名字是一样的,begin函数是指向vector第一个位置;end函数是指向vector的最后一个位置,所以我们可以通过这两个函数,轻而易举的去实现vector的遍历操作,它的用法和小编讲的string类是类似的,小编也不多废话了,直接告知各位它们的用法:

using namespace std;
int main()  //这里小编并没有写头文件,只是简单展示它的用发,各位读者朋友尝试的时候不要忘记加vector的头文件
{
    vector<int> s1 = {1,2,3,4,5};
    auto it = s1.begin();
    while(it != s1.end())
    {
        cout << *it << " ";
    }
    return 0;
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.2.2.rbegin + rend

这两个函数也是一个我们比较熟悉的函数了,这俩函数比上面两个函数多了个r,这个r其实是reverse,中文翻译就是反向的意思,它意味着此时的rbegin指向的其实是最后一个位置,而rend指向的是第一个位置,当然它不是倒着读取数据的,而是通过某些特殊操作来实现的,它也被称之为反向迭代器,对于反向迭代器的具体讲述,小编会在下一个容器list讲述,下面我展示一下这两个函数的使用方法。

using namespace std;
int main()
{
    vector<int> s1 = {1,2,3,4,5};
    auto it = s1.rbegin();
    while(it != s1.end())
    {
        cout << *it << " ";
    }
    return 0;
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

以上便就是迭代器的使用,它的使用方法和string类是很像的,所以容器的功能使用之间是有相似性的,所以小编很多地方就不细讲了(嘻嘻偷个懒),当然迭代器我们实现了,范围for我们自然而然也可以去使用了,但是没必要单独拿出来讲了,下面小编就展示一下范围for是如何进行使用。

2.2.3.范围for
using namespace std;
int main()
{
    vector<int> s1 = {1,2,3,4,5};
    for(auto e : s1)
    {
        cout << e << " ";
    }
    return 0;  //运行结果我就不展示了,上面的begin的运行结果就是范围for的运行结果。
}

2.3.vector空间增长问题

当然作为容器,难免会有扩容操作,会有查询有效元素个数操作,string类同样我也讲述了很多涉及空间的函数,当然vector我也会去讲,下面我就分别讲述这些功能的使用。

容量空间接口说明
size获取数据个数
capacity获取容量大小
empty判断是否为空
resize改变vector的size
reserve改变vector的capacity
2.3.1.size

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=C%3A%5CUsers%5C86186%5CAppData%5CRoaming%5CTypora%5C
typora-user-images%5Cimage-20241014234113979.png&pos_id=img-anfB84jt-1730534829947)

这个函数的功能和它的名字是一样的,它的作用是返回有用数据的大小的,简单来说就是顺序表的时候我们写过返回有效元素个数那个函数的功能,下面小编直接告知用法:

using namespace std;
vector<int> s1 = {1,2,3,4};
cout << s1.size() << " ";  //这里会直接返回4,因为有效元素个数就是4,小编就不费力在发截图了
2.3.2.capacity

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个函数的功能也是很简单,它是用来返回我们开辟vector容器空间总大小的,对标顺序表中的_capacity,下面小编展示其用法:

using namespace std;
vector<int> s1 = {1,2,3,4};
cout << s1.capacity() << " ";  //这里的返回值看编译器是如何开辟的,每个编译器可能这里对标的都不同
2.3.3.empty

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个函数的功能同样也是和它的名字相关,它是用来判定vector容器空间是否是空的,如果是空的就返回一个非0数,如果是空的就返回0,和顺序表我们写过的判空函数功能上是一致的,下面小编直接展示它的用法:

using namespace std;
vector<int> s1 = {1,2,3};
if(!s1.empty())  //这里的!表明着如果empty是真那么就变为假,如果是假那就变为真。
{
    cout << 1 << endl;  //这里肯定是会打印1的,因为此时的s1并不是空的。
}
2.3.4.resize

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个函数也是一个很重要的函数,它是负责对size进行修改的,如果resize里面的数小于size原来的数的话,那么会进行缩容操作,也就是会删除多余的数据,只保留resize里面个数的数据;如果resize里面的数大于size原来数的话,那么会进行扩容操作,当然也可以写都扩容成哪个数,它的功能也是比较容易理解的,下面小编就展示它是如何使用的:

using namespace std;
vector<int> s1 = {1,2,3,4,5};
for(auto e : s1)
{
    cout << e << " ";
}
cout << endl;
s1.resize(12,1);
for(auto e : s1)
{
    cout << e << " ";
}
cout << endl;

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.3.5.reserve

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个函数的功能小编在讲述string类的时候也说过,它的作用是用来进行预留空间的或者扩容空间的,一般我们在写一些涉及到空间的函数的时候,我们都可以用reserve来进行预开辟一块空间,从而减小空间的浪费,在一些大型的项目中它是有奇效的,由于难度不算大,下面小编展示一下这个函数的用法:

using namespace std;
vector<int> s1 = {1,2,3,4};
s1.reserve(100);

以上便就是vector空间增长相关的函数,当然还有很多函数小编并没有书写,那一些函数就留给读者朋友自行探索了,下面我们继续加快脚步,进入vector的增删查改操作。

2.4.vector的增删查改

小编在前面说了,vector相当于我们之前学习过的顺序表,所以vector也是会有增删查改操作的,当然,我们之后要学习的其他容器同样也是有增删查改操作的,下面我们分别对这些函数进行讲解。

2.4.1.push_back

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个函数想必各位学过数据结构的读者朋友都不会太陌生了,当然可能有很多还没学过数据结构的读者朋友,在这里小编还是推荐各位读者朋友去学一学数据结构的,它对于我们学习STL有着很大的帮助,当然直接学习STL也是没问题的,这里不多废话了,这个函数的功能是尾插,也就是在最后一个位置插入数据,它的用法是很简单的,下面小编代码展示一下它的用法:

using namespace std;
vector<int> s1;
s1.push_back(1);
s1.push_back(2);
s1.push_back(3);
s1.push_back(4);  //下面小编通过范围for展示一下它的运行结果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.4.2.pop_back

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个函数同样也是一个很常见的函数,它和上面的函数作用正好相反,上面进行的是尾插操作,这里进行的是尾删操作,也就是说把尾部的数据进行删除,当然如果是一个空的vector,他是会报assert错误的,因为这个是空的,所以不能再进行删除操作了,下面小编就展示一下它的用法:

using namespace std;
vector<int> s1 = (1,2,3,4);
s1.pop_back();
s1.pop_back();
s1.pop_back();//这里小编在通过范围for给各位看看这个函数的效果
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
2.4.3.find

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个函数可能会有很多读者朋友会很奇怪,这个函数没有出现在vector容器的介绍里,为什么还能用这个find函数呢?因为这个find函数是属于一个算法模版里面的,这个find函数同样也是一个模版函数,它可以支持很多容器去调用它,如果把它分别的写在每一个容器里面,就体现不出泛型编程的特点了,所以语言的设计者们把find函数包装成了模版函数,以方便后面各种容器的使用,对于find函数,这个函数的功能也是通过名字就可以体现出来,他是寻找指定数据的,如果找到了可以返回指定数据的位置,是以迭代器作为返回值的,下面小编就展示一下这个函数的用法:

using namespace std;
vector<int> s1 = {1,2,3,4,5};
int x;
cin >> x;
auto it = find(s1.begin(),s1.end(),x);//这里补充一点,这里还是通过给迭代器区间来查找相关的值,这个迭代器区间可以覆盖完vector区间,也可以选择不覆盖,这里会返回迭代器类型,auto关键字一用一个不吱声
2.4.4.insert

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个函数我也在顺序表讲过,它的功能是在指定位置插入数据,我们可以在刚开始插入数据,也可以在最后位置插入数据,同样也可以从中间位置插入数据,用我的话说:想插哪里就插哪里,它插入的位置也是要用迭代器进行表示的,下面小编直接展示它的用法了:

using namespace std;
vector<int> s1 = {1,2,3,4,5};
s1.insert(s1.begin() + 2,12);  //第一个参数一定要是迭代器类型的,通过我们看他的函数介绍便可以看出来

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.4.5.swap

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个函数也是一个比较常用的函数,它是用来进行对于两个vector对象内容的交换的,它的功能很简洁,所以小编也不多废话了,下面直接展示这个功能的使用:

using namespace std;
vector<int> s1 = {1,2,3,4,5};
vector<int> s2 = {5,6,7,8,9};
s1.swap(s2); //小编通过遍历的方式来帮助各位读者朋友了解他俩是否真的交换了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.4.6.operator[]

这个运算符重载也算是一个老朋友了,小编在前面string类的时候就说过这个运算符,它的重载是为了帮助我们更好的进行遍历数组,众所周知,遍历一个容器的方法一般有三种(期待后面的学习让我打脸),[]运算符重载便算是其中一种运算符重载,迭代器也算是一种,范围for是最后一种,对于这个[]的使用,和我们使用数组中的[]一样,我们仅需在对象后面加上[],里面的数代表我们要访问哪个数的数据,下面小编展示它的用法。

using namespace std;
vector<int> s1 = {1,2,3,4,5,6};
for(size_t i = 0 ; i < s1.size() ; i++)
{
    cout << s1[i] << " ";
}
cout << endl;

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

以上便就是小编所想要讲述的vector一些接口的使用,各位读者朋友要好好掌握这些接口的使用,小编在当初写STL初阶的时候就说过,对于STL的使用,我们有三种境界,能用,能理,能扩展,此时我们就是能用的环节,下一篇文章小编将会讲述vector的一些底层的实现,到时候小编会带领各位简单看一下vector的源码的,敬请期待吧,希望我不会又是嘴上说说。

![![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://i-blog.csdnimg.cn/direct/1580b03010cf4ba7b3981e5d75849b82.jpeg)

3.总结

此时,这篇文章的内容小编算是写完了,对于这篇文章的书写,小编觉着还是有些地方是不错的,希望以后的我对于容器的书写会越来越熟练,这篇文章我在很早之前就创作完成了,不知道以后的我会选择在何时进行发布,希望以后的我看到这里的时候,会比当初写这篇文章的我代码功力更加高深一点。如果文章有错误,可以在评论区指出,我会定期看评论处理问题的,那么我们下一篇文章见啦!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

转载自CSDN-专业IT技术社区

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/effort123_/article/details/143452208

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--