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

STL之vecor的使用(超详解)

 

目录

 1. C/C++中的数组

1.1. C语言中的数组

1.2. C++中的数组 

 2. vector的接口

2.1. vector的迭代器 

2.2. vector的初始化与销毁 

2.3. vector的容量操作 

2.4. vector的访问操作 

2.5. vector的修改操作 


💓 博客主页:C-SDN花园GGbond

⏩ 文章专栏:玩转c++

 1. C/C++中的数组

1.1. C语言中的数组

在 C 语言中,数组是一组相同类型元素的有序集合。与字符串类似,它的大小在编译时就已经确定,不可更改。 

//大小为5的整型数组
int arr1[5] = { 1,2,3,4,5 };
//大小为5的浮点型数组
double arr2[5] = {0.0};

1.2. C++中的数组 

同样与string类似,C++为了更加方便就引入了一个支持可动态大小数组的序列容器vecotr。其特点如下:

 

  1. vector是可变大小的序列容器,采用连续存储空间存储元素,可通过下标高效访问。
  2. 与数组不同,vector大小可动态改变,由容器自动处理。
  3. vector本质上用动态分配数组存储元素,插入新元素时可能重新分配空间,即分配新数组并移动全部元素,此操作时间代价高,但不是每次插入都重新分配。
  4. vector会分配额外空间适应增长,不同库策略不同,但重新分配通常是对数增长间隔,使末尾插入元素能在常数时间完成。
  5. dequelistforward_list相比,vector访问元素及末尾添加和删除元素更高效,非末尾的删除和插入操作效率低,且统一的迭代器和引用更好。
//整型数组
vector<int> v1;
//浮点型数组
vector<double> v2;

使用vector都需要包含头文件#include<vector>。并且vector是一个模版类,所以在使用时需要显示实例化。 

 

 2. vector的接口

介绍一些vector的常见接口,因为很多接口的作用都与string的接口非常类似,所以很多就不在详细说明,具体也可以参考vector文档。

4cf179dc487747cbb791b073911b00f3.png

  下面我们开始研究他的使用,为了能够更好的测试,我们先实现一个打印容器元素的函数,vector底层是数组,所以有三种访问方式:下标访问、迭代器访问、范围for(本质也是迭代器)

void Printf(vector<int>& v)
{//下表遍历cout << "下表遍历:";for (size_t i = 0; i < v.size(); i++){cout << v[i];}cout << endl;//迭代器遍历cout << "迭代器遍历:";vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it;it++;}cout << endl;cout << "范围for遍历:";for (auto e : v){cout << e;}cout << endl;
}
int main()
{vector<int> v = { 1,2,3,4,5,6,7,8,9 };Printf(v);//Test01();return 0;
}

 57eac87fa68d443db7ed5129175398f1.png

 ​​​​​​

2.1. vector的迭代器 

同样的vector中也存在迭代器iterator,因为定义在vector类中,所以其需要通过域作用限定符访问——vector<类型>::iterator

下面将介绍的begin(),end(),rbeign(),rend()的使用访问方法与string中的几乎一摸一样,我们直接上实例演示:

#include<iostream>
#include<vector>using namespace std;
void Test01()
{vector<int> v = { 1,2,3,4,5,6,7,8,9 };cout << "顺序遍历:";vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it;it++;}cout << endl;cout << "逆序遍历:";vector<int>::reverse_iterator rit = v.rbegin();while (rit != v.rend()){cout << *rit;rit++;}cout << endl;}
int main()
{Test01();return 0;
}

093772b6c25f4fd2a8634c094427e8ec.png

 

当然vector也支持const_iterator,用法也类似,这里就不在赘述。 

2.2. vector的初始化与销毁 

60befd5fa70d4c28b67fc30196b9e7c5.png

(1) 空容器构造函数(默认构造函数)
构造一个没有元素的空容器。
(2) 填充构造函数
构造一个包含n个元素的容器。每个元素都是val的副本。
(3) 范围构造器
构造一个包含与范围[first,last)一样多的元素的容器,每个元素都按照相同的顺序从该范围内的相应元素构造而成。
(4) 复制构造函数
构造一个容器,其中包含x中每个元素的副本,顺序相同。
 

c7001ccbe26d422da35a785a836479e1.png

同样的vector也支持多种构造函数,拷贝构造以及赋值运算符重载。 

void Test02()
{//无参构造vector<int> v1;Print(v1);//有参构造,n个位置初始化vector<int> v2(5, 2);Print(v2);//有参构造,n个位置调用T类型的默认构造vector<int> v3(5);Print(v3);//拷贝构造vector<int> v4(v3);Print(v4);//迭代器区间构造(传string的迭代器区间)string s("hello world");vector<int> v5(s.begin(), s.end());Print(v5);//迭代器区间构造(传vctor的迭代器区间)vector<int> v6(v5.begin(), v5.end());Print(v6);//赋值重载v1 = v6;cout << &v1 << "   " << &v6 << endl;//深拷贝Print(v1);//特殊的赋值方式vector<int> v7{ 1,2,3,4,5,6,7,8 };Print(v7);
}

98d091b952164f39b9eb1bc71e6ac6b2.png

2.3. vector的容量操作 

0f433b82d99d4bb9b03c7e754cc93593.png

d4c5b5393fea4b67a25b66ef3754eb11.png

vector类中,同样可以通过size()容器的有效长度;capacity()返回容器的容量大小。

void Test03()
{vector<int> v1;cout << v1.size() << endl;cout << v1.capacity() << endl;vector<int> v2 = { 0,1,2,3,4,5 };cout << v2.size() << endl;cout << v2.size() << endl;
}

12b8ab8d05524637b37183d3a5064fa4.png

在初始化时,vecotr中的sizecapacity一般相同。这时我们也可以通过以下程序探究一下其扩容机制: 

void Test04()
{size_t sz;vector<int> v;sz = v.capacity();cout << "making v grow" << endl;for (int i = 0; i < 100; i++){v.push_back(i);if (sz != v.capacity()){sz = v.capacity();cout << "capacity changed  " << v.capacity() << endl;}}
}
int main()
{Test04();return 0;
}

c34dee28ec704cb29486fb593477407d.png

在VS环境下,vector一般是以1.5倍扩容。但是在Linux环境下一般就以2倍扩容。 

58c314016a714161b67b9c59b0c61a4a.png

a2458ec7c562403b807c6a0ea95b76ba.png

要求容器减少容量以适应其大小。

该请求是非绑定的,容器实现可以自由地进行优化,使向量的容量大于其大小。

这可能会导致重新分配,但对向量大小没有影响,也不能改变其元素。

 

ae966670b2264115809eafc566891532.png

 

有效长度与容量操作 

 vector中的resize()reserve()。其实他们的用法与特点也是与string类中的相同

当n<sz时,reserve并不会发生任何改变,resize会删除有效字符到指定大小。
当sz<n<capcity时,reserve并不会发生任何改变,resize会补充有效字符(默认为0)到指定大小。
当n>capacity时,reserve会发生扩容,resize会补充有效字符(默认为0)到指定大小。

void Test06()
{vector<int> v1 = { 1,2,3,4,5 };cout << "v1的有效长度为:" << v1.size() << endl;cout << "v1的容量大小为:" << v1.capacity() << endl;v1.reserve(10);cout << "reserve(10)后:" << endl;cout << "v1的有效长度为:" << v1.size() << endl;cout << "v1的容量大小为:" << v1.capacity() << endl;cout << endl;v1.resize(8, 10);for (auto& e : v1){cout << e << " ";}cout << endl;cout << "v1的有效长度为:" << v1.size() << endl;cout << "v1的容量大小为:" << v1.capacity() << endl;v1.resize(3);for (auto& e : v1){cout << e << " ";}cout << "v1的有效长度为:" << v1.size() << endl;cout << "v1的容量大小为:" << v1.capacity() << endl;}int main()
{Test06();return 0;
}

3268a39a4ef64316b184f7eed9ff4b9b.png

2.4. vector的访问操作 

 7c91343943e74656b453ac8d519baa86.png

a125abd95aca431599e5f9ec7fbf9629.png

void Test07()
{vector<int> v = { 1,2,3,4,5 };for (int i = 0; i < v.size(); i++){cout << v.at(i) << " ";}cout << endl;for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;cout << "front:" << v.front() << endl;cout << "back:" << v.back() << endl;
}int main()
{Test07();return 0;
}

f8c3d76fef5347e3a9bc1c070ea4ad0c.png

2.5. vector的修改操作 

0fac8b321376493ca30627b92c9e9080.png

d8105e101d1a4b98bb8fcf4b2f9cfc9c.png

首先先介绍最简单的四个函数push_back()pop_back()assign()swap()

void Test7()
{vector<int> v = { 1,2,3,4,5,6 };cout << "back:" << v.back() << endl;//尾插v.push_back(7);//尾删cout << "back:" << v.back() << endl;v.pop_back();cout << "back:" << v.back() << endl;vector<int> vv = { 6,5,4,3,2,1 };//n个val赋值给原数组vv.assign(3, 2);for (int i = 0; i < vv.size(); i++){cout << vv[i] << " ";}cout << endl;vv.swap(v);for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;for (int i = 0; i < vv.size(); i++){cout << vv[i] << " ";}
}

1a2941ef5d104f62b9d3f0903f4be33a.png

介绍insert()与·earse()的用法,这两个函数的用法就与string中的有所不同。首先是insert()函数: 

5995e0b2240946769db167b728c1232f.png

指定位置插入,要注意的是这里不再像string一样,用的size_t 的pos,vector虽然也可以用下标访问,但是为了承接后面STL其他不支持下标访问的容器,所以这边的pos用的是迭代器类型 

void Test8()
{vector<int> myvector(3, 100);vector<int>::iterator it = myvector.begin();//1.向指定位置插入一个元素it = myvector.insert(it, 200);cout << "myvector contains:";for (it = myvector.begin(); it < myvector.end(); it++)cout << ' ' << *it;cout << endl;//2.向指定位置插入n个元素myvector.insert(it, 2, 300);cout << "myvector contains:";for (it = myvector.begin(); it < myvector.end(); it++)cout << ' ' << *it;cout << endl;//3.向指定位置插入一段迭代器区间it = myvector.begin();vector<int> anothervector(2, 400);cout << "myvector contains:";for (it = myvector.begin(); it < myvector.end(); it++)cout << ' ' << *it;cout << endl;it = myvector.begin();myvector.insert(it + 2, anothervector.begin(), anothervector.end());//4.向指定位置插入一段迭代器区间int myarray[] = { 501,502,503 };myvector.insert(myvector.begin(), myarray, myarray + 3);cout << "myvector contains:";for (it = myvector.begin(); it < myvector.end(); it++)cout << ' ' << *it;cout << endl;
}

e8bde24df4f24e38a0ffb45c8fae61e7.png

 

erase()

 

删除单个元素: 当你需要删除向量中的某个特定元素时,可以使用 erase 函数,并传递一个指向该元素的迭代器。这将删除该元素,并使后续元素向前移动一个位置。

删除多个元素: erase 函数还可以接受两个迭代器参数,表示要删除的元素范围(左闭右开区间)。这允许你一次性删除多个连续的元素。

无论是哪种形式,erase 的返回值都是一个迭代器,指向被删除元素之后的位置(即第一个未被删除的元素)。如果删除的是容器中的最后一个元素或所有元素,则返回 vector::end() 迭代器。

void Test9()
{//1.删除迭代器所指元素vector<int> myvector;for (int i = 1; i <= 10; i++) myvector.push_back(i);vector<int>::iterator it = myvector.erase(myvector.begin() + 5);it = myvector.erase(it);//2.删除一段迭代器区间it = myvector.erase(myvector.begin(), myvector.begin() + 3);cout << "myvector contains:";for (int i = 0; i < myvector.size(); ++i)cout << ' ' << myvector[i];cout << endl;
}

71f02f457ced4129891a9cc7506e745f.png

虽然看起来vector的insert()和erase()与string的没有什么区别,但是仔细观察就可以发现我们每次使用完迭代器之后都会更新,这是为什么呢?

主要还是因为我们每次插入数组都可能发生扩容,而扩容分为就地扩容与异地扩容。如果发生的异地扩容,这时的迭代器就不在指向原来的空间,而就指向一块释放的内存,我们一旦继续访问就会报错,这种现象我们称为迭代器失效。为了避免出现这种情况,所以我们在使用完迭代器之后需要更新。

f7c1c8f0879e47fca0352212fa0faecf.png

 

 

 

 

 

 

 

 

 

 

 

 

相关文章:

STL之vecor的使用(超详解)

目录 1. C/C中的数组 1.1. C语言中的数组 1.2. C中的数组 2. vector的接口 2.1. vector的迭代器 2.2. vector的初始化与销毁 2.3. vector的容量操作 2.4. vector的访问操作 2.5. vector的修改操作 &#x1f493; 博客主页&#xff1a;C-SDN花园GGbond ⏩ 文章专栏…...

SystemVerilog学习笔记(一):数据类型

在systemverilog中&#xff0c;主要包含以下数据类型&#xff1a; 4值类型2值类型数组字符串结构体和联合体枚举自定义类型 无符号数&#xff1a;无符号数的符号不使用任何标志&#xff0c;即无符号数只能存储正数。无符号二进制数的范围从 0 到 ((2^n) - 1)&#xff0c;n 表…...

Linux软件包管理与Vim编辑器使用指南

目录 一、Linux软件包管理器yum 1.什么是软件包&#xff1f; 2.什么是软件包管理器&#xff1f; 3.查看软件包 4.安装软件 ​编辑 5.卸载软件 Linux开发工具&#xff1a; 二、Linux编辑器---vim 1.vim的基本概念 (1) 正常/普通模式&#xff08;Normal mode&#xff0…...

每日一练 | 包过滤防火墙的工作原理

01 真题题目 包过滤防火墙对哪一层的数据报文进行检查&#xff1f; A. 应用层 B. 物理层 C. 网络层 D. 链路层 02 真题答案 C 03 答案解析 包过滤防火墙是一种基本的安全设备&#xff0c;它通过检查进出网络的数据包来决定是否允许该数据包通过。 这种类型的防火墙主要关注…...

AR眼镜方案_AR智能眼镜阵列/衍射光波导显示方案

在当今AR智能眼镜的发展中&#xff0c;显示和光学组件成为了技术攻坚的主要领域。由于这些组件的高制造难度和成本&#xff0c;其光学显示模块在整个设备的成本中约占40%。 采用光波导技术的AR眼镜显示方案&#xff0c;核心结构通常由光机、波导和耦合器组成。光机内的微型显示…...

SpringBoot(十九)创建多模块Springboot项目(完整版)

之前我有记录过一次SpringBoot多模块项目的搭建,但是那一次只是做了一个小小的测试。只是把各模块联通之后就结束了。 最近要增加业务开发,要将目前的单模块项目改成多模块项目,我就参照了一下我上次搭建的流程,发现总是有报错。上次搭建的比较顺利,很多细枝末节也没有仔细…...

Navicat 17 功能简介 | 单元格编辑器

Navicat 17 功能简介 | 单元格编辑器 本期&#xff0c;我们一起了解 Navicat 17 出色的数据操作功能的单元格编辑器。单元格编辑器支持文本、十六进制、图像和网页四种格式的数据编辑&#xff0c;位于底部的编辑器窗格&#xff0c;为你编辑更大容量的数据信息提供足够的显示和操…...

MySQL【四】

插入数据 向数据表中插入一行数据 INSERT|REPLACE INTO 表名[(字段列表)] VALUES(值列表); ########## 在s表中插入一条记录&#xff1a;学号为s011,姓名为李思&#xff0c;性别为默认值&#xff0c;计算机专业 ########## insert into s(sno,sname,dept)values(s011,李思,计…...

简单叙述 Spring Boot 启动过程

文章目录 1. 准备阶段&#xff1a;应用启动的入口2. 创建 SpringApplication 对象&#xff1a;开始启动工作3. 配置环境&#xff08;Environment&#xff09;&#xff1a;识别开发环境与生产环境4. 启动监听器和初始化器&#xff1a;感知启动的关键事件5. 创建 ApplicationCont…...

微信小程序自定义tabbar;禁用某个tab;修改某个tab的样式

微信小程序自定义tabbar&#xff1b;禁用某个tab&#xff1b;修改某个tab的样式 原本使用本身的tabBar就已经很舒服了&#xff0c;很合适了的&#xff0c;但是总有一些脑洞大开的产品和客户&#xff0c;给你搞点多样式&#xff0c;没办法牛马就得去做咯&#xff0c;现在就给大…...

力扣113:路径总和II

给你二叉树的根节点 root 和一个整数目标和 targetSum &#xff0c;找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum 22 输出&a…...

JavaScript字符串常用方法

在JavaScript中&#xff0c;字符串是用来表示文本数据的基本数据类型。字符串可以用单引号()、双引号(")、或反引号()包裹。JavaScript中的字符串是不可变的&#xff0c;也就是说&#xff0c;字符串的值一旦创建就无法更改&#xff0c;但可以创建新字符串来替换原有字符串…...

xtu oj 加一

样例输入# 2 4 1 2 3 4 4 3 2 4 1样例输出# 3 5 解题思路&#xff1a;最小操作次数一定是把所有数变成数组中最大值max。 1、找最大值&#xff0c;一开始我把max初始值设为0&#xff0c;如果a[i]>max,maxa[i],WA了。又看了一遍题目&#xff0c;发现所有整数的绝对值小于…...

QTcpSocket 服务端和客户端

前提&#xff1a; pro文件中添加 QT network 服务端主要采用信号槽机制&#xff0c;代码如如下 核心代码头文件#ifndef TCPSERVER_H #define TCPSERVER_H#include <QObject>#include <QTcpServer> #include <QTcpSocket> #include <QDebug> #inclu…...

Isaac Sim+SKRL机器人并行强化学习

目录 Isaac Sim介绍 OmniIssacGymEnvs安装 SKRL安装与测试 基于UR5的机械臂Reach强化学习测评 机器人控制 OMNI GYM环境编写 SKRL运行文件 训练结果与速度对比 结果分析 运行体验与建议 Isaac Sim介绍 Isaac Sim是英伟达出的一款机器人仿真平台&#xff0c;适用于做机…...

项目中用户数据获取遇到bug

项目跟练的时候 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading ‘code’) at Proxy.userInfo (user.ts:57:17) 因此我想要用result接受信息的时候会出错&#xff0c;报错显示为result.code没有该值 导致我无法获取到相应的数据 解决如下 给…...

SpringSecurity+jwt+captcha登录认证授权总结

SpringSecurityjwtcaptcha登录认证授权总结 版本信息&#xff1a; springboot 3.2.0、springSecurity 6.2.0、mybatis-plus 3.5.5 认证授权思路和流程&#xff1a; 未携带token&#xff0c;访问登录接口&#xff1a; 1、用户登录携带账号密码 2、请求到达自定义Filter&am…...

项目技术栈-解决方案-web3去中心化

web3去中心化 Web3 DApp区块链:钱包:智能合约:UI:ETH系开发技能树DeFi应用 去中心化金融P2P 去中心化网络参考Web3 DApp 区块链: 以以太坊(Ethereum)为主流,也包括Solana、Aptos等其他非EVM链。 区块链本身是软件,需要运行在一系列节点上,这些节点组成P2P网络或者半…...

【AI声音克隆整合包及教程】第二代GPT-SoVITS V2:创新与应用

一、引言 随着科技的迅猛发展&#xff0c;声音克隆技术已经成为一个炙手可热的研究领域。SoVITS&#xff08;Sound Voice Intelligent Transfer System&#xff09;&#xff0c;作为该领域的先锋&#xff0c;凭借其卓越的性能和广泛的适用性&#xff0c;正在为多个行业带来前所…...

分清数据链路层、网络层、传输层的区别,以及这些层面的代表协议

目录 数据链路层 网络层 传输层 数据链路层 OSI模型的第二层&#xff0c;负责在相邻节点之间传输帧&#xff0c;处理帧的封装、地址、差错控制和流量控制等。确保数据在物理介质上可靠地传输&#xff0c;并为上层协议提供服务。 以太网&#xff08;Ethernet&#xff09;&…...

git没有识别出大写字母改成小写重命名的文件目录

Git 默认不会跟踪大写字母和小写字母的区别&#xff0c;因为在大多数文件系统中&#xff0c;大写字母和小写字母被认为是相同的文件&#xff0c;只有在区分大小写的文件系统中&#xff08;如 macOS 的 HFS 或 Windows 的 NTFS&#xff09;&#xff0c;这才是一个问题。 如果重命…...

自己动手写Qt Creator插件

文章目录 前言一、环境准备1.先看自己的Qt Creator IDE的版本2.下载源码 二、使用步骤1.参考原本的插件2.编写自定义插件1.cmakelist增加一个模块2.同理&#xff0c;qbs文件也增加一个3.插件源码 三、效果总结 前言 就目前而言&#xff0c;Qt Creator这个IDE&#xff0c;插件比…...

数据重塑:长宽数据转换【基于tidyr】

在数据分析和可视化过程中&#xff0c;数据的组织形式直接影响着我们能够进行的分析类型和可视化效果。这里简单介绍两种常见的数据格式&#xff1a;长格式&#xff08;Long Format&#xff09;和宽格式&#xff08;Wide Format&#xff09;&#xff0c;以及如何使用tidyr包进行…...

多模态大模型开启AI社交新纪元,Soul App创始人张璐团队亮相2024 GITEX GLOBAL

随着AI在全球范围内的加速发展和广泛应用,各行业纷纷在此领域发力。作为全球最大的科技盛会之一,2024年的GITEX GLOBAL将目光再次聚焦于人工智能的飞速发展,吸引了超过6700家来自各个领域的企业参与。在这样的背景下,Soul App作为国内较早将AI技术应用于社交领域的平台,首次亮相…...

实验6记录网络与故障排除

实验6记录网络与故障排除 实验目的及要求&#xff1a; 通过实验&#xff0c;掌握如何利用文档记录网络设备相关信息并完成网络拓扑结构的绘制。能够使用各种技术和工具来找出连通性问题&#xff0c;使用文档来指导故障排除工作&#xff0c;确定具体的网络问题&#xff0c;实施…...

QEMU 模拟器中运行的 Linux 系统

这两个文件通常用于在 QEMU 模拟器中运行的 Linux 系统&#xff0c;具体作用如下&#xff1a; 1. linux-aarch64-qemu.ext4&#xff1a; - **文件类型**&#xff1a;这是一个文件系统镜像文件&#xff0c;通常是 ext4 文件系统格式。 - **作用**&#xff1a;它包含了 Li…...

Ceph PG(归置组)的状态说明

Ceph PG&#xff08;Placement Group&#xff09;的状态反映了Ceph集群中数据的健康状况和分布情况。以下是Ceph PG的一些常见状态&#xff1a; Creating&#xff1a;创建状态。在创建存储池时&#xff0c;会创建指定数量的归置组&#xff08;PG&#xff09;。Ceph在创建一或多…...

Docker使用docker-compose一键部署nacos、Mysql、redis

下面是一个简单的例子&#xff0c;展示如何通过Docker Compose文件部署Nacos、MySQL和Redis。请确保您的机器上已经安装了Docker和Docker Compose。 1&#xff0c;准备好mysql、redis、nacos镜像 sudo docker pull mysql:8 && sudo docker pull redis:7.2 &&…...

HTTP常见的状态码有哪些,都代表什么意思

HTTP 协议定义了一系列的状态码&#xff0c;用于描述服务器对客户端请求的处理结果。这些状态码分为五个类别&#xff0c;每个类别都有特定的用途。 常见状态码 1开头 信息性状态码 这些状态码表示请求已被接收&#xff0c;继续处理。 100 Continue&#xff1a;客户端应继续…...

WebKit的Windows接口(适用2024年11月份版)

WebKit的Windows接口 使用cairo作为图形后端&#xff0c;libcurl作为网络后端。并且它只支持64位的Windows。 安装开发工具 安装带有“使用c进行桌面开发”工作负载的最新Visual Studio。 Activate Developer Mode.激活开发者模式。Build-webkit脚本创建一个指向生成的comp…...