当前位置: 首页 > news >正文

C++STL详解(三)——vector的介绍和使用

文章目录

  • 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<int> v1;   

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

vector<int> v2(10, 2);

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

vector<int>v3(v2);

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

vector<int> v4(v2.begin(), v2.end());

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

vector<int> 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<int> 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 <int>v(10, 6);vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << endl;it++;}cout << endl;
}

rbegin和rend

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

insert 和erase

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

int main()
{vector<int> 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<int> v;v.push_back(1); //尾插元素1v.push_back(2); //尾插元素2v.push_back(3); //尾插元素3v.push_back(4);v.push_back(5);vector<int>::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<int> 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<int> 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 <int> 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 <int> 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。
在这里插入图片描述

相关文章:

C++STL详解(三)——vector的介绍和使用

文章目录vector的介绍vector的使用vector的定义方式vector的空间增长问题reserve和resizevector的迭代器使用begin 和endrbegin和rendinsert 和erasefind函数元素访问vector迭代器失效问题1&#xff1a;inserse插入扩容时空间销毁造成野指针问题2&#xff1a;erase删除或者inse…...

GEBCO海洋数据下载

一、数据集简介 GEBCO&#xff08;General Bathymetric chart of the Oceans&#xff09;旨在为世界海洋提供最权威的、可公开获取的测深数据集。 目前的网格化测深数据集&#xff0c;即GEBCO_2022网格&#xff0c;是一个全球海洋和陆地的地形模型&#xff0c;在15角秒间隔的…...

【C++容器】vector、map、hash_map、unordered_map四大容器的性能分析【2023.02.28】

摘要 vector是标准容器对数组的封装&#xff0c;是一段连续的线性的内存。map底层是二叉排序树。hash_map是C11之前的无序map&#xff0c;unordered_map底层是hash表&#xff0c;涉及桶算法。现对各个容器的查询与”插入“性能做对比分析&#xff0c;方便后期选择。 测试方案…...

ACM-蓝桥杯训练第一周

&#x1f680;write in front&#x1f680; &#x1f4dd;个人主页&#xff1a;认真写博客的夏目浅石.CSDN &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​ &#x1f4e3;系列专栏&#xff1a;ACM周训练题目合集.CSDN &#x1f4ac;总结&#xff1a…...

python基础—字符串操作

&#xff08;1&#xff09;字符串&#xff1a; Python内置了一系列的数据类型&#xff0c;其中最主要的内置类型是数值类型、文本序列&#xff08;字符串&#xff09;类型、序列&#xff08;列表、元组和range&#xff09;类型、集合类型、映射&#xff08;字典&#xff09;类型…...

【Spring】通过JdbcTemplate实现CRUD操作

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 通过JdbcTemplate实现 增删查改一、添加相关依…...

实战|掌握Linux内存监视:free命令详解与使用技巧

文章目录前言一. free命令介绍二. 语法格式及常用选项三. 参考案例3.1 查看free相关的信息3.2 以MB的形式显示内存的使用情况3.3 以总和的形式显示内存的使用情况3.4 周期性的查询内存的使用情况3.5 以更人性化的形式来查看内存的结果输出四. free在脚本中的应用总结前言 大家…...

嵌入式入门必看!调试工具安装——基于 AM64x核心板

本章节内容是为评估板串口安装USB转串口驱动程序。驱动适用于CH340、CH341等USB转串口芯片。 USB转串口驱动安装 适用安装环境:Windows 7 64bit、Windows 10 64bit。 本文测试板卡为创龙科技SOM-TL64x核心板,它是一款基于TI Sitara系列AM64x双核ARM Cortex-A53 + 单/四核Cort…...

JAVA开发(java类加载过程)

1、java语言的平台无关性。 因为java语言可以跑在java虚拟机上&#xff0c;所以只要能装java虚拟机的地方就能跑java程序。java语言以后缀名 .java为文件扩展名。通过java编译器javac编译成字节码文件.class 。java字节码文件通过java虚拟机解析运行。所以java语言可以说是编译…...

【vulhub漏洞复现】Thinkphp 2.x 任意代码执行

一、漏洞详情影响版本 thinkphp 2.x但是由于thinkphp 3.0版本在Lite模式下没有修复该漏洞&#xff0c;所以也存在该漏洞漏洞原因&#xff1a;e 和 /e模式匹配路由&#xff1a;e 配合函数preg_replace()使用, 可以把匹配来的字符串当作正则表达式执行; /e 可执行模式&#xff0c…...

LeetCode 1145. 二叉树着色游戏 -- 简单搜索

二叉树着色游戏 提示 中等 199 相关企业 有两位极客玩家参与了一场「二叉树着色」的游戏。游戏中&#xff0c;给出二叉树的根节点 root&#xff0c;树上总共有 n 个节点&#xff0c;且 n 为奇数&#xff0c;其中每个节点上的值从 1 到 n 各不相同。 最开始时&#xff1a; 「一…...

HyperGBM的三种Early Stopping方式

本文作者&#xff1a;杨健&#xff0c;九章云极 DataCanvas 主任架构师 很多机器学习框架如都提供了Early Stopping策略&#xff0c;主要用来防止模型过拟合。和模型训练提前停止的目标不同&#xff0c;AutoML的Early Stopping策略更多考虑的是算力消耗和模型质量的平衡。 通…...

心系区域发展,高德用一体化出行服务平台“聚”力区域未来

交通&#xff0c;是城市的血脉。通过对人、资源、产业的连接&#xff0c;交通建设往往是城市和区域经济发展的前提。不过&#xff0c;在度过了“要想富&#xff0c;先修路”的初级建设阶段后&#xff0c;交通产业内部也出现了挑战&#xff0c;诸如城市秩序、发展成本、用户使用…...

AI画图_stable-diffusion-webui安装使用指南(1)

本文章适用于: 有一定学习能力和钻研能力&#xff0c;遇到问题能合理使用搜索引擎尝试解决问题的人想在windows系统中尝试使用AI作画工具stable-diffusion-webui进行绘画的人有一定的计算机基础&#xff08;会魔法上网、知道 python和Git&#xff09;和英文阅读能力的人显卡为…...

浅谈MySQL主从复制

目录 1.MySQL主从复制是什么 2.MySQL主从复制的意义 3.MySQL主从复制原理 4.数据同步一致性问题 5.实现方式 1.MySQL主从复制是什么 MySQL主从复制就是指数据可以从一台MySQL的主节点复制到一个或多个从节点。 MySQL默认采用异步复制方式&#xff0c;这样从节点不用一直访…...

docker-compose安装kafka和php简单测试

docker-compose.yml内容&#xff1a; version: 3.1 services: zookeeper: container_name: zookeeper image: zookeeper:3.6 ports: - 2181:2181 kafka: image: wurstmeister/kafka container_name: kafka depends_on: - zookeeper …...

【蓝桥云课】快速幂

问题描述&#xff1a;快速求aba^bab 方法一&#xff1a;常规方法相乘a∗a∗a∗a∗...∗aa*a*a*a*...*aa∗a∗a∗a∗...∗a 方法二&#xff1a;分治方法求aba^bab ab{1,b0a,b1ab2⋅ab2,b为偶数ab−12⋅ab12,b为奇数a^b\begin{cases} 1& \text{,b0}\\ a& \text{,b1}\\ a…...

解决windows安装wxPython安装失败、速度过慢及PyCharm上wx包爆红问题

网上关于wxPython安装失败&#xff0c;安装速度过慢&#xff0c;以及安装成功后PyCharm中import wx仍然爆红的文章有很多&#xff0c;也特别杂&#xff0c;解决起来特别困难&#xff0c;今天在这里对问题的处理进行一个整合&#xff0c;希望能帮助到大家。 安装wxPython这里运用…...

封装小程序request请求[接口函数]

在这篇小程序API的Promise化文章中讲到小程序官方提供的异步API都是基于回调函数来实现的&#xff0c;在大量的使用这种回调函数就会造成回调地狱的问题&#xff0c;以及代码的可读性和可维护性差&#xff0c;通过对小程序API的Promise化能解决&#xff0c;那么本篇是来讲进行对…...

嵌入式 STM32 通讯协议--MODBUS

目录 一、自定义通信协议 1、协议介绍 2、网络协议 3、自定义的通信协议 二、MODBUS通信协议 1、概述 2、MODBUS帧结构 协议描述 3、MODBUS数据模型 4、MODBUS事务处理的定义 5、MODBUS功能码 6、功能码定义 7、MODBUS数据链路层 8、MODBUS地址规则 9、MO…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

Spring Boot 实现流式响应(兼容 2.7.x)

在实际开发中&#xff0c;我们可能会遇到一些流式数据处理的场景&#xff0c;比如接收来自上游接口的 Server-Sent Events&#xff08;SSE&#xff09; 或 流式 JSON 内容&#xff0c;并将其原样中转给前端页面或客户端。这种情况下&#xff0c;传统的 RestTemplate 缓存机制会…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S &#xff08;client/server 客户端/服务器&#xff09;&#xff1a;由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序&#xff0c;负责提供用户界面和交互逻辑 &#xff0c;接收用户输入&#xff0c;向服务器发送请求&#xff0c;并展示服务…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...