ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

【C++】vector 容器超全详解|新手入门学习(构造函数、迭代器、容量操作、增删查改,迭代器失效和二维vector)

【C++】vector 容器超全详解|新手入门学习(构造函数、迭代器、容量操作、增删查改,迭代器失效和二维vector) 文章目录前言一、vector 是什么二、vector 的构造函数三、vector 迭代器1、四种迭代器2、四种遍历方式四、vector 容量操作1、函数使用2、vector 的扩容机制了解3、优化效率技巧提前 reserve五、vector 增删查改1、接口总览2、代码使用六、大坑vector 迭代器失效1、什么是迭代器失效2、两种导致失效的场景场景 1扩容导致失效空间变了场景 2erase 删除导致失效位置变了3、迭代器失效的通用解决办法七、vector 二维数组以杨辉三角为例1、基本用法2、经典案例杨辉三角总结前言C 语言里我们用数组大小固定想扩容就得手动realloc又麻烦又容易出错。到了 C有了vector—— 一个可以自动增长的动态数组不用自己管内存想加就加、想删就删可以说非常方便。本文主要讲解构造函数、迭代器、容量操作、增删查改迭代器失效和二维vector等内容帮助新手快速入门。提示以下是本篇文章正文内容下面案例可供参考一、vector 是什么vector 英文翻译过来叫“向量”你可以把它理解成一个可以自动扩容的动态数组。和普通数组比vector有三大优势自动管理内存不用手动申请释放内存空间不够会自动扩容支持随机访问和数组一样可以用方括号[]下标访问丰富的接口插入、删除、查找、交换…… 全都有现成的。使用 vector 需要包含头文件#include vector且在std命名空间下。二、vector 的构造函数vector 有多种构造方式最常用的有 4 种构造函数功能说明vectorT v无参构造一个没有数据的 vectorvectorT v(n, val)构造一个有 n 个元素的值为 val 的 vectorvectorT v(v2)拷贝构造vectorT v(first, last)用迭代器区间构造补充vectorT v(n, val)也可以不传 val用vectorT v(n)表示构造一个有 n 个元素的值为 0 的vector。T表示传入的数据类型。#includeiostream#includevectorusingnamespacestd;intmain(){vectorintv1;// 空的int vector//vectorint v2(5); // 5个0vectorintv2(5,10);// 5个10vectorintv3(v2);// 拷贝构造v3vectorintv4(v2.begin(),v2.end());// 迭代器区间构造// 还可以用数组构造intarr[]{1,2,3,4,5};vectorintv5(arr,arrsizeof(arr)/sizeof(int));return0;}三、vector 迭代器迭代器是 STL 的通用遍历方式vector 的迭代器本质就是原生指针用起来非常方便。1、四种迭代器迭代器功能begin() / end()正向迭代器begin 指向第一个元素end 指向最后一个元素的下一个位置rbegin() / rend()反向迭代器rbegin 指向最后一个元素rend 指向第一个元素的前一个位置cbegin() / cend()const 正向迭代器只读不可改crbegin() / crend()const 反向迭代器也是只读不可改注end()、rend() 都是哨兵位迭代器不指向有效元素因此不能被解引用。2、四种遍历方式#includeiostream#includevectorusingnamespacestd;intmain(){vectorintv;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);// 方式1下标[]遍历最常用像数组一样for(size_t i0;iv.size();i)coutv[i] ;coutendl;// 方式2正向迭代器vectorint::iterator itv.begin();while(it!v.end()){cout*it ;it;}coutendl;// 方式3反向迭代器从后往前vectorint::reverse_iterator ritv.rbegin();while(rit!v.rend()){cout*rit ;rit;}coutendl;// 方式4范围for最简洁的方法是C11新增的语法for(autoe:v)coute ;coutendl;return0;}技巧点用auto自动推导迭代器类型不用写长长的vectorint::iterator。四、vector 容量操作函数功能说明size()返回有效元素个数capacity()返回底层总容量empty()判断vector是否为空resize(n, val)把有效元素个数改成 n多出的用 val 填充reserve(n)预留 n 个元素的空间只改容量不改有效个数1、函数使用#includeiostream#includevectorusingnamespacestd;intmain(){vectorintv;coutv.size()endl;// 0coutv.capacity()endl;// 0coutv.empty()endl;// 1空v.push_back(1);v.push_back(2);v.push_back(3);coutv.size()endl;// 3coutv.capacity()endl;// 容量自动扩容大于等于size// resize改变有效元素个数v.resize(5,0);// 变成5个元素新增的位置用0填充 → 1 2 3 0 0v.resize(2);// 变成2个元素 → 1 2coutv.capacity()endl;// 注意resize只改sizecapacity不会缩小// reserve只预留空间不改sizev.reserve(100);// 容量变成100但size还是2coutv.size()endl;// 2coutv.capacity()endl;// 100return0;}2、vector 的扩容机制了解vector 空间不够时会自动扩容但不同编译器扩容倍数不一样VSPJ 版 STL按1.5 倍扩容GSGI 版 STL按2 倍扩容这里用 VS 来演示#includeiostream#includevectorusingnamespacestd;intmain(){vectorintv;size_t szv.capacity();coutmaking v grow:endl;for(inti0;i100;i){v.push_back(i);if(sz!v.capacity()){szv.capacity();coutcapacity changed: szendl;}}return0;}3、优化效率技巧提前 reserve在使用vector处理大量数据时如果知道大概要存多少个元素提前用reserve预留空间可以避免边插入边扩容大幅提升效率。intmain(){vectorintv;v.reserve(100);// 提前预留100个空间for(inti0;i100;i)v.push_back(i);// 全程不扩容效率高return0;}五、vector 增删查改1、接口总览函数功能说明push_back(x)尾插一个元素最常用pop_back()尾删一个元素insert(pos, x)在 pos 位置前插入元素 xerase(pos)删除 pos 位置的元素swap(v)交换两个 vector 的内容operator[]下标访问最常用find(first, last, x)查找元素算法库函数不是成员函数注意find函数在algorithm头文件里不是 vector 的成员函数2、代码使用#includeiostream#includevectorusingnamespacestd;intmain(){vectorintv;// 尾插v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);// v: 1 2 3 4// 尾删v.pop_back();// v: 1 2 3// 任意位置插入v.insert(v.begin(),0);// 开头插入0 → 0 1 2 3v.insert(v.begin()2,99);// 第3个位置插入99 → 0 1 99 2 3// 任意位置删除v.erase(v.begin());// 删除第一个 → 1 99 2 3v.erase(v.begin()1);// 删除第二个 → 1 2 3// 查找注意find是算法库的不是vector的成员函数autoposfind(v.begin(),v.end(),2);if(pos!v.end())cout找到了下标pos-v.begin()endl;// 交换vectorintv2(5,10);v.swap(v2);// 交换v和v2的内容return0;}六、大坑vector 迭代器失效1、什么是迭代器失效vector 的迭代器本质就是指针。迭代器失效 迭代器指向的空间被释放了再用就会访问非法内存程序崩溃。2、两种导致失效的场景场景 1扩容导致失效空间变了所有可能引起底层空间改变的操作都可能导致迭代器失效resize、reserve、insert、push_back、assign等。#includeiostream#includevectorusingnamespacestd;intmain(){vectorintv{1,2,3,4,5};autoitv.begin();v.reserve(100);// 扩容旧空间被释放it失效了// 再用it就是非法访问程序崩溃while(it!v.end()){cout*it ;it;}return0;}原因扩容时开了新空间、释放了旧空间而it还指向旧空间的地址。场景 2erase 删除导致失效位置变了erase删除元素后后面的元素会往前搬移。如果删除的是最后一个元素删完后pos刚好等于end就失效了。以下是错误的写法#includeiostream#includevectorusingnamespacestd;// 错误写法删除所有偶数会崩溃或结果不对intmain(){vectorintv{1,2,3,4};autoitv.begin();while(it!v.end()){if(*it%20)v.erase(it);// erase后it失效了it;// 失效的迭代器再会崩溃或者结果与预期不符}return0;}正确操作是接收erase返回值erase会返回下一个有效位置的迭代器用返回值更新it就不会失效了。以下是正确的写法#includeiostream#includevectorusingnamespacestd;intmain(){vectorintv{1,2,3,4};autoitv.begin();while(it!v.end()){if(*it%20)itv.erase(it);// 用返回值更新itelseit;}return0;}3、迭代器失效的通用解决办法操作完之后如果还要用迭代器重新赋值一下就好。比如扩容之后重新it v.begin();就不会有问题了。#includeiostream#includevectorusingnamespacestd;intmain(){vectorintv{1,2,3,4,5};autoitv.begin();v.reserve(100);// 扩容旧空间被释放it失效了itv.begin();// 重新赋值while(it!v.end()){cout*it ;it;}return0;}七、vector 二维数组以杨辉三角为例vector 的元素也可以是 vector这样就形成了二维数组而且每行长度可以不一样比 C 语言的二维数组灵活多了。1、基本用法#includeiostream#includevectorusingnamespacestd;intmain(){// 3行的二维数组每行是一个vectorintvectorvectorintvv(3);vv[0].push_back(1);vv[1].push_back(1);vv[1].push_back(2);vv[2].push_back(1);vv[2].push_back(2);vv[2].push_back(3);// 遍历二维vectorfor(size_t i0;ivv.size();i){for(size_t j0;jvv[i].size();j)coutvv[i][j] ;coutendl;}return0;}2、经典案例杨辉三角118. 杨辉三角classSolution{public:vectorvectorintgenerate(intnumRows){vectorvectorintvv(numRows);// 每行大小设为i1全部初始化为1for(inti0;inumRows;i)vv[i].resize(i1,1);// 中间元素 上一行两个相加for(inti2;inumRows;i)for(intj1;ji;j)vv[i][j]vv[i-1][j]vv[i-1][j-1];returnvv;}};119. 杨辉三角 IIclassSolution{public:vectorintgetRow(introwIndex){vectorvectorintvv(rowIndex1);// 每行大小设为i1全部初始化为1for(inti0;irowIndex;i)vv[i].resize(i1,1);// 中间元素 上一行两个相加for(inti2;irowIndex;i)for(intj1;ji;j)vv[i][j]vv[i-1][j]vv[i-1][j-1];returnvv[rowIndex];}};总结本文主要是讲解了vector容器的用法和新手可能遇到的坑希望对大家有所帮助。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表