C++vector的使用方法
文章目录
- 一、vector的介绍
- 1. 文档链接
- 2. 简要介绍
- 二、vector的使用
- 1.vector的定义
- (1)构造函数
- (2)拷贝构造函数
- (2)赋值重载
- 2. vector 增删查改
- (1)operator []
- (2)push_back和pop_back
- (3)insert和erase
- (4)find查找
- 3. vector 空间增长问题
- (1)size和empty及capacity
- (2)resize和reserve
- (3 reserve
- (4 resize
- 4. vector iterator 的使用
- (1)begin和end
- (2)rbegin和rend
- (3)范围for
一、vector的介绍
1. 文档链接
参考文档

2. 简要介绍
- vector是表示可变大小数组的序列容器。
- 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
- 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
- vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
- 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
- 与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list统一的迭代器和引用更好。
二、vector的使用
1.vector的定义
| (constructor)构造函数声明 | 接口说明 |
|---|---|
| vector()(重点) | 无参构造 |
| vector(size_type n, const value_type& val = value_type()) | 构造并初始化n个val |
| vector (const vector& x); (重点) | 拷贝构造 |
| vector (InputIterator first, InputIterator last); | 使用迭代器进行初始化构造 |
| vector& operator= (const vector& x); | 赋值重载 |
(1)构造函数
- vector的构造函数主要有三种
- 无参构造
- 放入n个相同的数据
- 使用迭代器区间进行构造
其中的allocator是空间配置器,只是用来分配空间的,加快空间申请和释放的速度。

vector是一个模板类,在实例化的时候要指明其内置类型。
template < class T, class Alloc = allocator<T> > class vector;
void test1()
{vector<int> v1;//无参构造vector<int> v2(3, 2);//构造一个有3个2的vectorstring s1("abcd");vector<int> v3(s1.begin(), s1.end());//迭代器构造}


在迭代器构造的示例中我们可以看到v3的size是4,但是里面存的却不是字符abcd,那是因为我们实例化的时候类型写的是int,他这里发生了隐式类型转换。
如果想要看到正确的字符的话改成下面这样就好了
vector<char> v3;
vector<char>和string的区别:vector存的是一个一个的字符,结尾是没有'\0'的,而是string是字符串所以结尾会有'\0'
vector中不仅可以存自定义类型,它还可以放自定义类型,你创建的结构体什么的都可以放。因为【vector】是一个模版类,其会根据所传入的类型去做一个自动类型的推导,例如在vector中放入string对象,我们就可以直接这样写
vector<string> s1;
(2)拷贝构造函数

我们可以简单来看一下

void test2()
{vector<int> v1(3, 2);vector<int> v2(v1);//拷贝构造vector<int> v3 = v1;//这也是拷贝构造,不是赋值重载
}

(2)赋值重载


void test3()
{vector<int> v1(3, 2);vector<int> v2;v2 = v1;//赋值重载}

2. vector 增删查改
| vector增删查改 | 接口说明 |
|---|---|
| push_back(重点) | 尾插 |
| pop_back (重点) | 尾删 |
| find | 查找。(注意这个是算法模块实现,不是vector的成员接口) |
| insert | 在position之前插入val |
| erase | 删除position位置的数据 |
| swap | 交换两个vector的数据空间 |
| operator[] (重点) | 像数组一样访问 |
(1)operator []
在vector中对[]进行了运算符重载,使得我们可以像通过下标访问数组元素一样来访问vector,同时支持修改
- 下面是官方文档中的形式,虽然看起来很复杂,但是读者完全不用理会,会用就可以了
reference operator[] (size_type n);const_reference operator[] (size_type n) const;

void test4()
{string s1("hello,world");vector<char> v1(s1.begin(), s1.end());for (int i = 0; i < s1.size(); i++){cout << v1[i] << " ";}//支持访问cout << endl;v1[0] = 'x';v1[1] = 'y';//支持修改for (int i = 0; i < s1.size(); i++){cout << v1[i] << " ";}
}

(2)push_back和pop_back
在数组尾部插入一个元素和删除最后一个元素。


void test4()
{string s1("hello,");vector<char> v1(s1.begin(), s1.end());for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;v1.push_back('L');v1.push_back('i');v1.push_back('n');v1.push_back('u');v1.push_back('x');for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;v1.pop_back();v1.pop_back();v1.pop_back();v1.pop_back();v1.pop_back();v1.pop_back();for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}
}

如果我们这里采取string类作为【vector】的内置类型,然后通过三种形式往里面插入数据:
- 第一种是构造出具体的对象
- 第二种采取的是匿名对象
- 第三种采取的则是单参数的构造函数所引发的 隐式类型转换
void test5()
{vector<string> v;string name1("张三");v.push_back(name1);v.push_back(string("李四"));v.push_back("王五"); // 单参数的构造函数支持隐式类型转换
}

(3)insert和erase


insert有很多,这里仅仅展示部分常用的两参数的,第一个参数是要插入位置的迭代器,第二个是要插入的元素。
void test7()
{vector<string> v;v.push_back("张三");v.push_back("王五");v.insert(v.begin() + 1, "李四");//在begin的下一个位置插入一个元素for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;v.erase(v.begin());//删除begin位置的元素for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}}

如果想要删除指定元素,我们可以find和erase搭配使用
(4)find查找

find是在范围内查找,观察函数的参数我们可以知道如果要使用这个函数的话就需要先传入一个迭代器区间,然后传入一个值,在指定的区间内查找这个值。如果找到则返回指向改元素位置的迭代器,如果找不到那就返回最后的迭代器也就是end()
void test6()
{string s1("hello,world");vector<char> v1(s1.begin(), s1.end());std::vector<char>::iterator it = find(v1.begin(), v1.end(), 'w');if (it != v1.end()){cout << *it << endl;}}

我们可以搭配erase加循环使用,删除vector中所有的 ‘l’ 字符
void test6()
{string s1("hello,world");vector<char> v1(s1.begin(), s1.end());std::vector<char>::iterator it = find(v1.begin(), v1.end(), 'l');while (it != v1.end()){it = v1.erase(it);it = find(it, v1.end(), 'l');}for (auto e : v1){cout << e << " ";}cout << endl;}

3. vector 空间增长问题
| 容量空间 | 接口说明 |
|---|---|
| size | 获取数据个数 |
| capacity | 获取容量大小 |
| empty | 判断是否为空 |
| resize(重点) | 改变vector的size |
| reserve (重点) | 改变vector的capacity |
(1)size和empty及capacity
size就是获取容器中有几个元素,capacity就是容器的容量
capacity和size是不一样的,你可以开10个空间但只放5个数据,此时size就是5,而capacity就是10.
void test10()
{vector<int> v(5, 10);cout << v.size();
}
可以看到我们插入了5个10,所以size是5,capacity也是5.

empty就是判断容器是否有元素,没有元素返回1,有元素返回0
void test11()
{vector<int> v;cout << v.empty() << endl;//没元素所以为真,输出1v.push_back(1);cout << v.empty();//插入一个元素后不为空,输出0
}

(2)resize和reserve
vector是可以自动扩容的,但频繁扩容是浪费时间的,所以我们可以提前开足够的空间,提高效率。
我们可以探索一下vector的扩容机制
void TestVectorExpand()
{size_t sz;vector<int> v;sz = v.capacity();cout << "making v grow:\n";for (int i = 0; i < 100; ++i){v.push_back(i);if (sz != v.capacity()){sz = v.capacity();cout << "capacity changed: " << sz << '\n';}}
}
可见在vs中,vector是按1.5倍的规则扩容的,我们去Linux平台下再去试试。

可以看到在Linux平台下是按照2倍的扩容逻辑走的。可见不同地方vector的实现方法略有区别。

(3 reserve
reserve是开好空间但不填充元素,所以size是不改变的,只有capacity会改变。因为size没改变,所以不能通过[]来访问没元素的位置。
void TestVectorExpandOP()
{vector<int> v;size_t sz = v.capacity();v.reserve(100); // 提前将容量设置好,可以避免一遍插入一遍扩容cout << "making bar grow:\n";for (int i = 0; i < 100; ++i){v.push_back(i);if (sz != v.capacity()){sz = v.capacity();cout << "capacity changed: " << sz << '\n';}}
}
可以看到避免了频繁扩容

(4 resize
resize是开好指定的空间并填充默认值,capacity和size都会改变
可以看到size和capacity都是3,填充的默认值我们没有指定,所以默认填充的是0。

当然我们可以指定填充的内容,比如这里我们指定填充数字10

接下来我们说一下常见的错误
大家可以看看下面的代码有什么问题,是不是乍一看好像每什么问题,但是一运行直接寄了。
void test13()
{vector<int> v1;v1.reserve(10);for (size_t i = 0; i < 10; i++){v1[i] = i;}
}

- 大家要关注前面的reserve(10),我们在上面说到对于【reserve】而言只是做的扩容而已,即只变化capacity,而不会变化size
- 另一点,对于v1[i]我们上面在讲元素访问的时候有说到过,这是下标 + []的访问形式,在出现问题的时候会直接给出断言错误。因为这里我们在【reserve】的时候只是开出了指定的空间,但size还是为0,此时去访问的时候肯定就出错了
改正方法就是将reserve改成resize即可
可以看到成功运行

4. vector iterator 的使用
| iterator的使用 | 接口说明 |
|---|---|
| begin + end(重点) | 获取第一个数据位置的iterator/const_iterator, 获取最后一个数据的下一个位置的iterator/const_iterator |
| rbegin + rend | 获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置的reverse_iterator |

(1)begin和end
- 和【string】中一样,每个迭代器也是具有两种形式,第一个呢是具有读写的,第二个则是只读的const迭代器
- begin获取一个字符的迭代器
- end获取最后一个字符下一个位置的迭代器


迭代器的理解,迭代器呢可以说是STL中很重要的一部分。简单来说迭代器就是用来遍历或访问容器中的数据的,我们暂时可以把迭代器想象成指针,通过指针的++或者–加解引用的方式,我们就可以遍历一个数组,或者访问数组中的元素。当然指针只是迭代器中的一种,迭代器要实现的目的就是通过++或者–能够遍历容器中所有的元素,我们数组是一段连续的空间,可以通过指针加一的方式遍历整个数组,但是如果是链表呢?这种情况下通过对每个指针++的操作就无法实现目的了,因此指针就不适合当迭代器了,我们就得封装新的迭代器。
void test8()
{string s1("hello,world");vector<char> v1(s1.begin(), s1.end());vector<char>::iterator it = v1.begin();while (it != v1.end()){cout << *it << " ";//通过解引用迭代器获取容器中的元素++it;//迭代器++,指向下一个位置}
}

(2)rbegin和rend
rbegin和rend是反向迭代器


反向迭代器呢顾名思义就是从反方向进行遍历
void test8()
{string s1("hello,world");vector<char> v1(s1.begin(), s1.end());vector<char>::iterator it1 = v1.begin();while (it1 != v1.end()){cout << *it1 << " ";++it1;}cout << endl;auto it2 = v1.rbegin();while (it2 != v1.rend()){cout << *it2 << " ";++it2;}
}

(3)范围for
既然支持迭代器的话,那肯定支持范围for的,我们可以来试试。
void test9()
{string s1("hello,world");vector<char> v1(s1.begin(), s1.end());for (auto e : v1){cout << e << " ";}
}
可以看到没有任何问题。

相关文章:
C++vector的使用方法
文章目录 一、vector的介绍1. 文档链接2. 简要介绍 二、vector的使用1.vector的定义(1)构造函数(2)拷贝构造函数(2)赋值重载 2. vector 增删查改(1)operator [](2&#x…...
视频生成模型Sora的全面解析:从AI绘画、ViT到ViViT、DiT、VDT、NaViT、VideoPoet
视频生成模型Sora的全面解析:从AI绘画、ViT到ViViT、DiT、VDT、NaViT、VideoPoet 真没想到,举例视频生成上一轮的集中爆发才过去三个月,没想OpenAI一出手,该领域又直接变天了自打2.16日OpenAI发布sora以来,不但把同时…...
4.1k star,官方出品的redis桌面管理工具——redislnsight
导航 令人抓狂的大key加载RedisInsight 简介RedisInsight的亮点GitHub 地址安装和使用RedisInsight 下载安装 使用RedisInsight redis数据库可视化直观的CLI(Command-Line Interface)日志分析和命令分析 结语参考 令人抓狂的大key加载 工欲善其事必先利…...
论文目录3:大模型时代(2023+)
1 instruction tuning & in context learning 论文名称来源主要内容Finetuned Language Models Are Zero-Shot Learners2021 机器学习笔记:李宏毅ChatGPT Finetune VS Prompt_UQI-LIUWJ的博客-CSDN博客 早期做instruction tuning的work MetaICL: Learning to …...
FPGA IBUFG
IBUFG和IBUFGDS的输入端仅仅与芯片的专用全局时钟输入管脚有物理连接,与普通IO和其它内部CLB等没有物理连接。 所以,IBUFG输入的不能直接接另外信号。 GTH transceiver primitives are called GTHE3_COMMON and GTHE3_CHANNEL in UltraScale FPGAs, an…...
探索数据结构:单链表的实战指南
✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:数据结构与算法 贝蒂的主页:Betty‘s blog 前言 在上一章节中我们讲解了数据结构中的顺序表,知道了顺序…...
短视频矩阵系统----矩阵系统源码搭建(技术门槛?)
短视频矩阵是什么意思?短视频矩阵的含义可以理解为全方位的短视频账号,通过不同的账号实现全方位的品牌展示。实际上是指一个短视频账号,通过不同的链接实现品牌展示,在不同的粉丝流量账号中互相转发同一个品牌,在主账…...
Spring事务注解@Transactional的流程和源码分析
Spring事务简介 Spring事务有两种方式: 编程式事务:编程式事务通常使用编程式事务管理API实现,比如Spring提供的PlatformTransactionManager接口,使用它手工编码去操控事务。声明式事务:注解式事务使用AOP࿰…...
在别的地方下载的二次封装Windows镜像怎么安装?GHO镜像详细安装教程
前言 在系统之家或者其他地方下载的镜像文件怎么装到电脑上? 首先要知道系统之家下载的Windows镜像文件基本上都是.iso结尾的,要进入到对应镜像包才能看出系统镜像是什么格式。 如何分辨镜像的格式 选择对应的.iso镜像,点击【鼠标右键】-【装…...
使用Lerna + Yarn Workspace管理Monorepo项目
1.前言 通常,我们会根据自身业务的实际情况,将通用的组件、逻辑等提取成NPM包,方便以后复用。但这些提取出来的NPM包可能互相之间存在依赖,如果仍然采用 Multirepo 的形式进行管理,则在包的版本管理、依赖管理、调试等…...
如何将gzip后缀压缩包重命名任意后缀名并依然通过gzip.open()读取压缩包文件内容
在 Python 中,gzip.open() 用于解压缩 .gz 后缀的文件。因此,如果您将文件的后缀从 .gz 更改为其他后缀,例如 .diy,然后尝试使用 gzip.open() 打开它,会导致失败,因为 Python 会尝试使用 gzip 解压缩它&…...
C语言从入门到精通 第十一章(文件操作)
写在前面: 本系列专栏主要介绍C语言的相关知识,思路以下面的参考链接教程为主,大部分笔记也出自该教程。除了参考下面的链接教程以外,笔者还参考了其它的一些C语言教材,笔者认为重要的部分大多都会用粗体标注…...
安装安卓studio无法下载sdk解决方法
安装安卓studio无法下载sdk的解决方法如下: 因为google被墙了,android sdk无法下载。 只要修改host文件,就可以下载sdk了。host文件的位置在:C:\Windows\System32\drivers\etc\hosts host文件添加如下内容: #google_…...
express+mysql+vue,从零搭建一个商城管理系统10--添加商品
提示:学习express,搭建管理系统 文章目录 前言一、新建models/goods.js二、新建routes/goods.js三、添加goods表四、添加商品总结 前言 需求:主要学习express,所以先写service部分 一、新建models/goods.js models/goods.js con…...
java实现大文件的分割与合并
最近遇到一个问题,某网盘上传文件时,文件大小超过了4个G ,不能上传,所以就想到了利用的java的IO流,将文件分割成多个小文件,上传到网盘上,等到需要用的时候,下载下来然后再进行文件的…...
【计网】TCP协议安全与风险:深入探讨网络通信的基石
🍎个人博客:个人主页 🏆个人专栏:Linux ⛳️ 功不唐捐,玉汝于成 目录 🌐前言 🔒正文 TCP (Transmission Control Protocol): UDP (User Datagram Protocol): HTTP (Hypertext Transfer …...
苹果App Store上架工具介绍
文章目录 摘要引言正文1. Xcode2. [appuploder](https://www.applicationloader.net/)3. [克魔助手](https://keymob.com/) 4.[ipa guard](https://www.ipaguard.com/)总结参考资料 摘要 苹果App Store作为iOS应用程序的主要分发渠道,上架应用程序需要遵守规定和通…...
TCP重传机制、滑动窗口、拥塞控制
一、总述 TCP,Transmission Control Protocol,是一个面向连接、基于流式传输的可靠传输协议,考虑到的内容很多,比如数据包的丢失、损坏、分片和乱序等,TCP协议通过多种不同的机制来实现可靠传输。今天,重点…...
electron+vue3全家桶+vite项目搭建【29】封装窗口工具类【3】控制窗口定向移动
文章目录 引入实现效果思路声明通用的定位对象主进程模块渲染进程测试效果 引入 demo项目地址 窗口工具类系列文章: 封装窗口工具类【1】雏形 封装窗口工具类【2】窗口组,维护窗口关系 封装窗口工具类【3】控制窗口定向移动 很多时候,我们想…...
深入了解304缓存原理:提升网站性能与加载速度
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...
手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...
