C++STL详解(三)——vector的介绍和使用
创始人
2024-05-27 09:03:14
0

文章目录

  • vector的介绍
  • vector的使用
    • vector的定义方式
    • vector的空间增长问题
      • reserve和resize
    • vector的迭代器使用
      • begin 和end
      • rbegin和rend
      • insert 和erase
      • find函数
      • 元素访问
    • vector迭代器失效问题
      • 1:inserse插入扩容时空间销毁造成野指针问题
      • 2:erase删除或者insert插入时元素移动迭代器问题:

vector的介绍

1: vector是表示可变大小数组的容器。
2:vector就像数组一样,也采用的连续空间来存储元素,这也意味着vector可以采用下标对vector的元素进行访问。
3:vector与普通数组不同的是,vector的大小是可以动态改变的。
4:vector需要分配大小时,其做法是,分配一个新的数组,然后将全部元素移入到这个数组当中,并且释放原来的空间。
5:由于vector采用连续的空间来存储元素,与其他动态序列容器相比,vector在访问元素的时候更加高效,在其末尾添加和删除元素相对高效,而对于不在其末尾进行的删除和插入操作效率则相对较低。

vector的使用

vector的定义方式

方式一:构造一个vector类型的容器。

vector v1;   

方式二: 构造一个含有n各val的vector容器

vector v2(10, 2);

方式三:vector容器的拷贝构造

vectorv3(v2);

方式四:使用迭代器区间构造(该方式也可用于构造其他容器,例如string类型。)

vector v4(v2.begin(), v2.end());

方式6:像C语言定义数组一样定义。

vector v5{ 1,2,3,4,5};

vector的空间增长问题

reserve和resize

reserve说明
1:改变容器的最大的最大容量,当我们所传的值大于容器当前的
capacity时,会将capacity扩大到该值。
2:当所给值小于容器当前的capacity是,reserve无效果。
resize说明
1:当所传值大于容器当前的size时,会将size扩大到所传值,扩大的元素为第二个所传值,如果用户没有给出,则编译器会给上缺省值为0;
2:当所传值小于容器当前的size时,则会将vector容器的size缩小到所传值大小。

int main()
{vector v(10, 2);v.resize(15);//扩容,并让size()大小为15,5个0用来填充。for (size_t i = 0; i < v.size(); ++i){cout << v[i] << " ";}cout << endl;v.resize(10); //让size()大小变为10,vector容量不变。for (size_t i = 0; i < v.size(); ++i){cout << v[i] << " ";}cout << v.capacity() << endl; //20return 0;
}

vector的迭代器使用

在这里插入图片描述

begin 和end

int main()
{vector v(10, 6);vector::iterator it = v.begin();while (it != v.end()){cout << *it << endl;it++;}cout << endl;
}

rbegin和rend

int main()
{vector v{ 1,2,3,4,5,6 };//反向迭代器遍历容器:reverse_iteratorvector::reverse_iterator rit = v.rbegin();while (rit != v.rend()){cout << *rit << " ";rit++;}cout << endl;return 0;
}

insert 和erase

insert函数可以在目标位置插入1个或者多个指定元素。
erase函数可以删除迭代器指定位置的元素,也可以使用迭代器
进行删除。(左闭右开)

int main()
{vector v;v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.pop_back();//插入位置,插入个数,插入值。v.insert(v.begin(), 3,1);for (size_t i = 0; i < v.size(); ++i){cout << v[i] << " ";}cout << endl;v.erase(v.begin(), v.begin() + 1);for (size_t i = 0; i < v.size(); ++i){cout << v[i] << " ";}cout << endl;return 0;
}

find函数

find函数说明:
使用find函数要确认所要删除位置的迭代器区间,第三个参数则要确定用户所要寻找的值。
如果find函数在所传的迭代器区间找到了目标元素,则返回目标元素迭代器,否则则返回end()位置迭代器。


int main()
{vector v;v.push_back(1); //尾插元素1v.push_back(2); //尾插元素2v.push_back(3); //尾插元素3v.push_back(4);v.push_back(5);vector::iterator it = v.begin();//在区间寻找值为2的元素,并返回对应迭代器。//auto 根据后面的返回值类型主动判断。auto  pos = find(it, it + 4, 2);if ( pos != v,end()){//删除pos所指的元素。v.erase(pos);}for (size_t i = 0; i < v.size(); ++i){cout << v[i] << " ";}cout << endl;return 0;
}

元素访问

vector中除了使用vector迭代器进行访问的,还可以使用[]操作符重载访问。

int main()
{vector v(10, 1);//使用“下标+[]”的方式遍历容器for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;return 0;
}

另外,vector还支持迭代器,这也就说明vector还支持范围for进行访问。

int main()
{vector v(10, 6);for (auto e : v){cout << e << " ";}cout << endl;return 0;
}

vector迭代器失效问题

1:inserse插入扩容时空间销毁造成野指针问题

例如,当我们从vector容器3的位置前插入30,不对vector进行扩容时,发现程序正常运行。
但是当我们插入数据时要对vector进行扩容却发现程序而不能崩溃了。

void test_vector1()
{vector  v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (auto e : v){cout << e << " ";}cout << endl;auto p = find(v.begin(), v.end(), 3));if (p != v.end()){v.insert(p, 30);}for (auto e : v){cout << e << " ";}}

原因
当我们插入30时会发生第二次扩容,此时find 找到了vector容器元素为3的位置并返回指向3的迭代器,但是因为vector扩容后会对这原来的vector空间销毁,此时返回的p并不是原来3的迭代器位置,此时p已经变成了野指针,insert时pos会导致导致程序崩溃。
以下insert 和 reserve 方法的底层实现:
在这里插入图片描述在这里插入图片描述
pos此时的值已经变成了随机值。
在这里插入图片描述
改善方法探讨:
我们可以在扩容后更新pos指向的元素的位置。但是此时又有一个问题,我们在扩容后重新修正了pos的位置时,却发现p依旧是失效的,原因是pos是形参,p是实参。形参的改变并不会影响到实参。
在这里插入图片描述
此时,我们可以在pos形参位置加入引用,但是当我们使用
v.begin()为实参传入时,却发现调用不成功,因为此时的v.begin()
返回的值具有常性,权限由小变大。
在这里插入图片描述

又或者我们可以返回pos位置的引用,又说明引用的值可以被修改,这又与STL insert方法的实现相违背。

解决方法
当使用insert后又要使用insert或者erase操作进行扩容或者缩容时,因为在insert时,扩容后已经重新对pos进行赋值,但是因为pos终究是形参的改变无法影响到实参,所以在insert后要使用变量去接受pos的位置。

void test_vector1()
{vector  v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (auto e : v){cout << e << " ";}cout << endl;auto p = find(v.begin(), v.end(), 3);if (p != v.end()){v.insert(p, 30);//插入一个数后及时接受pos的位置后才能继进行插入。auto p = find(v.begin(), v.end(), 3);v.insert(p, 30);}for (auto e : v){cout << e << " ";}}
int main()
{test_vector1();
}

2:erase删除或者insert插入时元素移动迭代器问题:

如果erase函数具有缩容功能时,也会导致迭代器失效,所以erase之后我们尽量不要直接对它进行访问。
第一种情况
程序正常运行:
如果我们插入5个元素,当it指向元素5时,it正好指向v.end(),所以程序正常退出。
在这里插入图片描述
第二种情况
程序崩溃:
如果我们插个4个元素,当it指向元素4进行删除后 it++,但是v.end()指向了元素3的下一个位置,而此时it又进行++,与v.end()正好错过了。所以本来应该删除4之后结束循环的,如今只能进行删除。如果一直循环下去的化,it就变成了野指针的,在erase中对野指针访问后就会造成程序崩溃。
在这里插入图片描述
第三种情况
程序结果不对:
当我们连续插入偶数时,it指向元素2删除后,原来在2后面的4向前移动了以为,在下一次while循环中,原本it指向4的现在指向了元素3,元素4未被删除。
在这里插入图片描述
解决方法
针对插入4个元素时,在不对迭代器i重新赋值时,我们可以当it指向偶数就删除,指向奇数就++;这样在最后删除4后,it就不会像之前++了,此时it指向的位置正好等于v.end(),结束循环。
在这里插入图片描述

再例如:我们在偶数之前插入这个偶数的两倍。
如果我们不对it进行操作,直接让it++后进行访问,
又因为再2的前面插入一个数后,此时的2已经在原来的位置基础上向后移动了以为,这样it又会指向元素2,此刻便会不断循环对2的前面一个元素插入数字。
造成程序崩溃。
在这里插入图片描述
解决办法
我们要解决插入元素后it一直指向同一个数问题,如果it指向偶数,可以在偶数前插入一个术后,it++两次,从而跳过已经插过数的偶数了。如果为奇数,则直接++it。
在这里插入图片描述

相关内容

热门资讯

安卓9系统怎样应用分身,轻松实... 你有没有发现,手机里的APP越来越多,有时候一个APP里还要处理好多任务,分身功能简直就是救星啊!今...
获取安卓系统的ip地址,轻松获... 你有没有想过,你的安卓手机里隐藏着一个神秘的IP地址?没错,就是那个能让你在网络世界里找到自己的小秘...
LG彩电安卓系统升级,畅享智能... 你家的LG彩电是不是最近有点儿“闹别扭”,屏幕上时不时地跳出个升级提示?别急,今天就来给你详细说说这...
阴阳师安卓苹果系统,安卓与苹果... 亲爱的玩家们,你是否曾在深夜里,手握手机,沉浸在阴阳师的神秘世界?今天,就让我带你一起探索这款风靡全...
华为安卓系统区别在哪,独特创新... 你知道吗?最近手机圈里可是热闹非凡,尤其是华为的新动作,让很多人眼睛都瞪大了。没错,我说的就是华为自...
怎么重新刷安卓手机系统,深度解... 手机用久了,是不是感觉卡顿得厉害?别急,今天就来教你怎么重新刷安卓手机系统,让你的手机焕然一新,速度...
刷正版安卓系统教程,刷正版安卓... 你有没有想过,让你的安卓手机焕然一新,体验一把正版系统的魅力呢?别急,今天就来手把手教你如何刷正版安...
移动支撑系统安卓版,助力移动办... 你有没有发现,现在的生活越来越离不开手机了?无论是工作还是娱乐,手机几乎成了我们生活的必需品。而今天...
安卓怎么进win系统界面,安卓... 亲爱的安卓用户,你是否曾幻想过在安卓设备上直接体验Windows系统的魅力?别再羡慕那些Window...
incall可以升级安卓系统吗... 你有没有想过,你的手机是不是也能像电脑一样,时不时地来个系统升级呢?今天,咱们就来聊聊这个话题——i...
安卓系统带农历软件,尽享传统节... 你知道吗?现在智能手机上有个特别实用的功能,那就是农历显示。对于咱们中国人来说,农历可是有着深厚的历...
安卓系统资源占用高,揭秘原因与... 你有没有发现,你的安卓手机最近变得越来越慢了?是不是觉得打开一个应用都要等半天,甚至有时候还会卡死?...
安卓10的系统有哪些,功能升级... 你有没有发现,你的安卓手机最近是不是变得有点不一样了?没错,就是那个神秘的安卓10系统!它就像一位魔...
固态硬盘系统迁移到安卓,固态硬... 你有没有想过,把你的固态硬盘系统迁移到安卓设备上,是不是能让你在移动办公或者娱乐时更加得心应手呢?想...
平板电脑能玩安卓系统吗,畅享丰... 你有没有想过,平板电脑竟然也能玩安卓系统?这可不是天方夜谭,而是科技发展的新趋势。想象你手中的平板瞬...
安卓刷精简系统下载,轻松打造高... 你有没有想过,你的安卓手机是不是有点儿“臃肿”了呢?运行速度慢,电池续航短,有时候还卡得要命。别急,...
安卓子系统windows11,... 你知道吗?最近科技圈可是炸开了锅,因为安卓子系统在Windows 11上的兼容性成了大家热议的话题。...
电脑里怎么下载安卓系统,电脑端... 你有没有想过,你的电脑里也能装上安卓系统呢?没错,就是那个让你手机不离手的安卓!今天,就让我来带你一...
索尼相机魔改安卓系统,魔改系统... 你知道吗?最近在摄影圈里掀起了一股热潮,那就是索尼相机魔改安卓系统。这可不是一般的改装,而是让这些专...
安卓系统哪家的最流畅,安卓系统... 你有没有想过,为什么你的手机有时候像蜗牛一样慢吞吞的,而别人的手机却能像风一样快?这背后,其实就是安...