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
。其特点如下:
vector
是可变大小的序列容器,采用连续存储空间存储元素,可通过下标高效访问。- 与数组不同,
vector
大小可动态改变,由容器自动处理。vector
本质上用动态分配数组存储元素,插入新元素时可能重新分配空间,即分配新数组并移动全部元素,此操作时间代价高,但不是每次插入都重新分配。vector
会分配额外空间适应增长,不同库策略不同,但重新分配通常是对数增长间隔,使末尾插入元素能在常数时间完成。- 与
deque
、list
和forward_list
相比,vector
访问元素及末尾添加和删除元素更高效,非末尾的删除和插入操作效率低,且统一的迭代器和引用更好。
//整型数组
vector<int> v1;
//浮点型数组
vector<double> v2;
使用vector
都需要包含头文件#include<vector>
。并且vector
是一个模版类,所以在使用时需要显示实例化。
2. vector的接口
介绍一些vector
的常见接口,因为很多接口的作用都与string
的接口非常类似,所以很多就不在详细说明,具体也可以参考vector文档。
下面我们开始研究他的使用,为了能够更好的测试,我们先实现一个打印容器元素的函数,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;
}
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;
}
当然vector
也支持const_iterator
,用法也类似,这里就不在赘述。
2.2. vector的初始化与销毁
(1) 空容器构造函数(默认构造函数)
构造一个没有元素的空容器。
(2) 填充构造函数
构造一个包含n个元素的容器。每个元素都是val的副本。
(3) 范围构造器
构造一个包含与范围[first,last)一样多的元素的容器,每个元素都按照相同的顺序从该范围内的相应元素构造而成。
(4) 复制构造函数
构造一个容器,其中包含x中每个元素的副本,顺序相同。
同样的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);
}
2.3. vector的容量操作
在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;
}
在初始化时,vecotr
中的size
与capacity
一般相同。这时我们也可以通过以下程序探究一下其扩容机制:
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;
}
在VS环境下,vector
一般是以1.5倍扩容。但是在Linux环境下一般就以2倍扩容。
要求容器减少容量以适应其大小。
该请求是非绑定的,容器实现可以自由地进行优化,使向量的容量大于其大小。
这可能会导致重新分配,但对向量大小没有影响,也不能改变其元素。
有效长度与容量操作
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;
}
2.4. vector的访问操作
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;
}
2.5. vector的修改操作
首先先介绍最简单的四个函数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] << " ";}
}
介绍insert()
与·earse()
的用法,这两个函数的用法就与string
中的有所不同。首先是insert()
函数:
指定位置插入,要注意的是这里不再像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;
}
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;
}
虽然看起来vector的insert()和erase()与string的没有什么区别,但是仔细观察就可以发现我们每次使用完迭代器之后都会更新,这是为什么呢?
主要还是因为我们每次插入数组都可能发生扩容,而扩容分为就地扩容与异地扩容。如果发生的异地扩容,这时的迭代器就不在指向原来的空间,而就指向一块释放的内存,我们一旦继续访问就会报错,这种现象我们称为迭代器失效。为了避免出现这种情况,所以我们在使用完迭代器之后需要更新。
相关文章:

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 ⏩ 文章专栏…...

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

Linux软件包管理与Vim编辑器使用指南
目录 一、Linux软件包管理器yum 1.什么是软件包? 2.什么是软件包管理器? 3.查看软件包 4.安装软件 编辑 5.卸载软件 Linux开发工具: 二、Linux编辑器---vim 1.vim的基本概念 (1) 正常/普通模式(Normal mode࿰…...
每日一练 | 包过滤防火墙的工作原理
01 真题题目 包过滤防火墙对哪一层的数据报文进行检查? A. 应用层 B. 物理层 C. 网络层 D. 链路层 02 真题答案 C 03 答案解析 包过滤防火墙是一种基本的安全设备,它通过检查进出网络的数据包来决定是否允许该数据包通过。 这种类型的防火墙主要关注…...

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

SpringBoot(十九)创建多模块Springboot项目(完整版)
之前我有记录过一次SpringBoot多模块项目的搭建,但是那一次只是做了一个小小的测试。只是把各模块联通之后就结束了。 最近要增加业务开发,要将目前的单模块项目改成多模块项目,我就参照了一下我上次搭建的流程,发现总是有报错。上次搭建的比较顺利,很多细枝末节也没有仔细…...
Navicat 17 功能简介 | 单元格编辑器
Navicat 17 功能简介 | 单元格编辑器 本期,我们一起了解 Navicat 17 出色的数据操作功能的单元格编辑器。单元格编辑器支持文本、十六进制、图像和网页四种格式的数据编辑,位于底部的编辑器窗格,为你编辑更大容量的数据信息提供足够的显示和操…...
MySQL【四】
插入数据 向数据表中插入一行数据 INSERT|REPLACE INTO 表名[(字段列表)] VALUES(值列表); ########## 在s表中插入一条记录:学号为s011,姓名为李思,性别为默认值,计算机专业 ########## insert into s(sno,sname,dept)values(s011,李思,计…...
简单叙述 Spring Boot 启动过程
文章目录 1. 准备阶段:应用启动的入口2. 创建 SpringApplication 对象:开始启动工作3. 配置环境(Environment):识别开发环境与生产环境4. 启动监听器和初始化器:感知启动的关键事件5. 创建 ApplicationCont…...

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

力扣113:路径总和II
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例 1: 输入:root [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum 22 输出&a…...
JavaScript字符串常用方法
在JavaScript中,字符串是用来表示文本数据的基本数据类型。字符串可以用单引号()、双引号(")、或反引号()包裹。JavaScript中的字符串是不可变的,也就是说,字符串的值一旦创建就无法更改,但可以创建新字符串来替换原有字符串…...

xtu oj 加一
样例输入# 2 4 1 2 3 4 4 3 2 4 1样例输出# 3 5 解题思路:最小操作次数一定是把所有数变成数组中最大值max。 1、找最大值,一开始我把max初始值设为0,如果a[i]>max,maxa[i],WA了。又看了一遍题目,发现所有整数的绝对值小于…...
QTcpSocket 服务端和客户端
前提: pro文件中添加 QT network 服务端主要采用信号槽机制,代码如如下 核心代码头文件#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是英伟达出的一款机器人仿真平台,适用于做机…...

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

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

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

【AI声音克隆整合包及教程】第二代GPT-SoVITS V2:创新与应用
一、引言 随着科技的迅猛发展,声音克隆技术已经成为一个炙手可热的研究领域。SoVITS(Sound Voice Intelligent Transfer System),作为该领域的先锋,凭借其卓越的性能和广泛的适用性,正在为多个行业带来前所…...
分清数据链路层、网络层、传输层的区别,以及这些层面的代表协议
目录 数据链路层 网络层 传输层 数据链路层 OSI模型的第二层,负责在相邻节点之间传输帧,处理帧的封装、地址、差错控制和流量控制等。确保数据在物理介质上可靠地传输,并为上层协议提供服务。 以太网(Ethernet)&…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...