STL之vector容器

vector的介绍

1.vector是可变大小数组的容器

2.像数组一样,采用连续的空间存储,也就意味着可以通过下标去访问,但它的大小可以动态改变

3.每次的插入都要开空间吗?开空间就要意味着先开临时空间,然后在拷贝旧的到新的上面,在释放原来的,就时间而言,这是一个相对代价很高的任务;显然这是不行的,vector的分配策略:会分配一些而外的空间以适应可能的增长,例如我们平时说的以1.5或者2倍的方式增容,不同的库选择不同的策略权衡空间的使用和重新分配,以至于在插入一个元素时能在常数时间内插入;

vector的使用

构造函数:

 

注意:这里的allocator_type是空间配置器,与内存池相关,可以暂时忽略

          这里的vector<int>要传模板,指明你每个元素里面存的类型是什么 

第一个能构造一个空的vector数组

第二个能构造4个元素,每个元素里面存100的数组

第三个传迭代器能根据迭代器构造出一个对象

第四个是拷贝构造函数 

如果第二个中我没有指定每个元素为100,它会根据你传的模板是什么初始化为啥,例如你传int就初始化为0

3种遍历方式

1.operator[]

因为底层是数组,所以重载了operator[]方便遍历

for(size_t i=0;i<vt.size();i++)
{cout<<vt[i]<<" ";
}

2.迭代器遍历

 

 可以看到vector容器提供了begin/end和rbegin/rend,这说明我们可以正反向遍历 

vector<int>::iterator it=vt.begin();
while(it!=vt.end())
{cout<<*it;it++;
}vector<int>::reverse_iterator rit=rbegin();
while(it!=rbegin())
{cout<<*it;it++;
}

3.返回for遍历:底层就是迭代器,只要能实现迭代器就能实现范围for

for(auto&e:vt)
{cout<<e;
}

注意:如果你有一个函数,例如打印函数,你是不想修改数组里面元素的值,那传参时需要传const修饰的数组,此时你在打印函数中使用迭代器,只能用const迭代器 

迭代器分两个版本,一个是const迭代器一个是普通迭代器

void Print(const vector<int>&vt)
{vector<int>::const_iterator it=vt.begin();while(it!=vt.end())
{
cout<<*it;
*it+=1;//这句是错的,你传了const就意味着你不能通过迭代器去修改
}
}

 capacity函数接口

size():顾名思义就是返回数组的大小,这里的大小是有效元素的大小

capacity():是返回这里数组的容量,也就是你动态开辟出来的大小

empty():判断是否为空;如果没有元素即返回true,有就返回false

resize():改变数组的size

reserve():改变数组的容量,如果提前知道空间可以减少增容的代价

注意:vs2022是以1.5倍增长,gcc是以两倍增长,两个用的STL版本不一样,vs使用PJ版本,gcc是用SGI版本

Modifiers函数接口

数组当然实现的是尾插和尾删,效率高,如果你有头插和头删最好别选vector(后面会介绍list和vector的优缺点)

push_back():尾插一个数据

pop_back():尾删一个数据

insert():任意位置的插入,在pos位置之前插入

注意:这里传迭代器 

erase():任意位置的删除,删除pos位置的元素,返回下一个元素的迭代器

注意:这里我们不知道要删除的元素的位置该如何找到呢?vector没有实现find

可以调用<algorithm>库实现的find

找到返回pos位置的迭代器,找不到返回end();

 swap():交换两个vector的数据空间

clear():清空元素,但开辟的空间没有释放

 重点谈迭代器失效问题

迭代器的主要作用是让算法不用关系底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T*。因此,迭代器失效,实际就是迭代器底层对应的指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果就是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)

第一种情况:

如果你先定义了迭代器vector<int>::iterator it=vt.begin();

然后在进行各种扩容操作reserve,resize,insert,assign,push_back等

然后在使用迭代器,那原来的指针it指向的的那块空间已经被释放了,因为你进行了扩容开辟了新空间,你在使用迭代器去解引用或者it!=vt.end()等操作都可能会造成程序崩溃

第二种情况:

比如你使用库实现的find去查找某个元素,会返回一个迭代器类型,然后在释放这个位置的元素

vector<int>::iterator pos=find(vt.begin(),vt.end(),3);
if(pos!=vt.end())
{erase(pos);
}
cout<<*pos<<;//此处会导致非法访问

erase删除pos位置之后,pos位置之后的元素会往前挪动,没有导致底层空间的改变,理论上讲迭代器是不会失效的,但是,如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,pos就会失效,因此删除vector中任意位置的元素是,vs就认为该位置迭代器失效了 

动态二维数组的理解:

我们如何创建一个二维数组,可以想象每个vector的元素都是一个vector<int>

vector<vector<int>> vv(5);

这里可以想象一个一维数组,有五个元素,每个元素都是一个vector<int> 

那我们如何初始化呢 

 第一种:我们学过vector<int> v(3,5)//这是创建3个元素,每个元素都是5,因此我们可以这与初始化二维数组,rows是行,每个元素是vector<int>(cols),initial)

int main() {// 定义二维数组的行数和列数int rows = 3;int cols = 4;// 初始值int initialValue = 0;// 创建并初始化二维 vectorstd::vector<std::vector<int>> twoDArray(rows, std::vector<int>(cols, initialValue));// 输出二维数组for (const auto& row : twoDArray) {for (int element : row) {std::cout << element << " ";}std::cout << std::endl;}return 0;
}

第二种:

可以创建好二维数组,在用循环依次填入数据 


int main() {// 定义二维数组的行数和列数int rows = 3;int cols = 4;// 初始值int initialValue = 0;// 创建空的二维 vectorstd::vector<std::vector<int>> twoDArray;// 逐行添加元素for (int i = 0; i < rows; ++i) {std::vector<int> row(cols, initialValue);twoDArray.push_back(row);}// 输出二维数组for (const auto& row : twoDArray) {for (int element : row) {std::cout << element << " ";}std::cout << std::endl;}return 0;
}

 第三种:使用c++11的初始化列表进行初始化

int main() {// 使用列表初始化创建二维 vectorstd::vector<std::vector<int>> twoDArray = {{1, 2, 3},{4, 5, 6},{7, 8, 9}};// 输出二维数组for (const auto& row : twoDArray) {for (int element : row) {std::cout << element << " ";}std::cout << std::endl;}return 0;
}

注意:当我们创建好了之后,可以像一个二维数组一样使用vv[i][j]去访问每个元素

实质就是operator[]重载运算符,第一个[]先和vv结合,第二个后结合就可以访问了 

 简单模拟实现vector容器、

我已经把代码上传gitee,有需要可以自己拿

 June: 这里包含我的c++和Linux及数据结构https://gitee.com/taifanshu/day2.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/79447.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[学成在线]22-自动部署项目

自动部署 实战流程 下边使用jenkins实现CI/CD的流程。 1、将代码使用Git托管 2、在jenkins创建任务&#xff0c;从Git拉取代码。 3、拉取代码后进行自动构建&#xff1a;测试、打包、部署。 首先将代码打成镜像包上传到docker私服。 自动创建容器、启动容器。 4、当有代…

74HC123的电路应用场景

74HC123的电路应用场景 **1. 引脚功能示例****2. 核心功能****&#xff08;1&#xff09;单稳态触发器****&#xff08;2&#xff09;双独立通道****&#xff08;3&#xff09;灵活触发方式** **3. 工作原理****4. 典型应用场景****&#xff08;1&#xff09;定时与延时控制***…

【人工智能】大模型安全的深度剖析:DeepSeek漏洞分析与防护实践

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 随着大语言模型(LLM)的广泛应用,其安全性问题日益凸显。DeepSeek作为中国领先的开源AI模型,以低成本和高性能著称,但近期暴露的数据库…

《ESP32音频开发实战:I2S协议解析与WAV音频录制/播放全指南》

前言 在智能硬件和物联网应用中&#xff0c;音频处理能力正成为越来越重要的功能——无论是语音交互、环境音采集&#xff0c;还是音乐播放&#xff0c;都离不开高效的音频数据传输与处理。而I2S&#xff08;Inter-IC Sound&#xff09;作为专为音频设计的通信协议&#xff0c…

大数据实时数仓的数据质量监控解决方案

实时数仓不仅仅是传统数据仓库的升级版,它更强调数据的实时性、流动性和高可用性,通过对海量数据的即时处理和分析,为企业提供近乎实时的洞察力。这种能力在金融、零售、制造、互联网等行业中尤为关键,例如,电商平台可以通过实时数仓监控用户行为,动态调整推荐算法;金融…

56认知干货:智能化产业

如果在不久的未来,一座高楼大厦的建设,只需将图纸输入系统,无数台机器人就能精准协作完成任务; 电影节的主角不再是人类,动漫与影视作品将不再需要人类创作; 当播种和收获的工作无人参与,所有过程都能自动化进行; 这将预示着我们将迎来一个智能化社会,在这个社会中,…

使用synchronized关键字同步Java线程

问题 在Java多线程编程中&#xff0c;你需要保护某些数据&#xff0c;防止多个线程同时访问导致数据不一致或程序错误。 解决方案 在需要保护的方法或代码段上使用synchronized关键字。 讨论 synchronized关键字是Java提供的同步机制&#xff0c;用于确保在同一时刻只有一…

MATLAB基于格拉姆角场与2DCNN-BiGRU的轴承故障诊断模型

本博客来源于CSDN机器鱼&#xff0c;未同意任何人转载。 更多内容&#xff0c;欢迎点击本专栏目录&#xff0c;查看更多内容。 目录 0 引言 1 格拉姆角场原理 2 2DCNN-BiGRU网络结构 3 应用实例 3.1 数据准备 3.2 格拉姆角场数据提取 3.3 网络模型搭建-重中之重 3.4 …

电气设备器件选型参数---断路器

断路器 一、基本电气参数 额定电压&#xff08;Ue&#xff09; 必须≥系统最高工作电压&#xff08;如380V、660V等&#xff09;。 注意直流/交流系统的区别&#xff0c;直流断路器需专门设计。 额定电流&#xff08;In&#xff09; 根据负载的持续工作电流选择&#xff0c;…

Linux常用命令30——groupadd创建新的用户组

在使用Linux或macOS日常开发中&#xff0c;熟悉一些基本的命令有助于提高工作效率&#xff0c;groupadd命令的功能是创建新的用户组。每个用户在创建时都有一个与其同名的基本组&#xff0c;后期可以使用groupadd命令创建出新的用户组信息&#xff0c;让多个用户加入指定的扩展…

微信小程序 自定义组件 标签管理

环境 小程序环境&#xff1a; 微信开发者工具&#xff1a;RC 1.06.2503281 win32-x64 基础运行库&#xff1a;3.8.1 概述 基础功能 标签增删改查&#xff1a;支持添加/删除单个标签、批量删除、重置默认标签 数据展示&#xff1a;通过对话框展示结构化数据并支持复制 动…

wpf CommandParameter 传递MouseWheelEventArgs参数 ,用 MvvmLight 实现

在 WPF 中使用 MVVM Light 框架传递 MouseWheelEventArgs 参数至 CommandParameter,可通过以下步骤实现: ‌1. XAML 中配置事件绑定‌ 在控件上通过 EventToCommand 绑定鼠标滚轮事件,并启用 PassEventArgsToCommand 属性以传递事件参数: <!-- 命名空间声明 --> x…

vmware diffy配置ollama 本机ip无法访问

防火墙直接关闭 本地测试&#xff0c;给它直接关了 ollama配置 vim /etc/systemd/system/ollama.service这是的配置 [Unit] DescriptionOllama Service Afternetwork-online.target[Service] Environment"OLLAMA_HOST0.0.0.0:11434" #Environment"OLLAMA_OR…

React--》掌握react构建拖拽交互的技巧

在这篇文章中将深入探讨如何使用react-dnd&#xff0c;从基础的拖拽操作到更复杂的自定义功能带你一步步走向实现流畅、可控且用户友好的拖拽体验,无论你是刚接触拖拽功能的初学者还是想要精细化拖拽交互的经验开发者&#xff0c;都能从中找到适合自己的灵感和解决方案。 目录 …

数据结构与算法:回溯

回溯 先给出一些leetcode算法题&#xff0c;以后遇见了相关题目再往上增加 主要参考代码随想录 2.1、组合问题 关于去重&#xff1a;两种写法的性能分析 需要注意的是&#xff1a;使用set去重的版本相对于used数组的版本效率都要低很多&#xff0c;大家在leetcode上提交&#x…

iview 分页改变每页条数时请求两次问题

问题 在iview page分页的时候&#xff0c;修改每页条数时&#xff0c;会发出两次请求。 iview 版本是4.0.0 原因 iview 的分页在调用on-page-size-change之前会调用on-Change。默认会先调用on-Change回到第一页&#xff0c;再调用on-page-size-change改变分页显示数量 此时就会…

一周学会Pandas2 Python数据处理与分析-Pandas2复杂数据查询操作

锋哥原创的Pandas2 Python数据处理与分析 视频教程&#xff1a; 2025版 Pandas2 Python数据处理与分析 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 前面我们学了.loc[]等几个简单的数据筛选操作&#xff0c;但实际业务需求往 往需要按照一定的条件甚至复杂的组合条件…

【Vue bug】:deep()失效

vue 组件中使用了 element-plus 组件 <template><el-dialog:model-value"visible":title"title":width"width px":before-close"onClose"><div class"container" :style"{height:height px}"&g…

Trae 安装第三方插件支持本地部署的大语言模型

Trae 安装第三方插件支持本地部署的大语言模型 0. 引言1. 安装插件 0. 引言 字节发布的 Trae IDE 一直不支持本地部署的的大语言模型。 Qwen3 刚刚发布&#xff0c;想在 Trae 中使用本地部署的 Qwen3&#xff0c;我们可以在 Trae 中安装其他插件。 1. 安装插件 我们可以安装…

JavaScript 中的 Proxy 与 Reflect 教程

目录 get 和 set 捕获器详解 为什么要用 Reflect? 使用语法间接调用内部方法 使用 Reflect 直接调用内部方法 对比总结: Reflect API 及其与 Proxy 的配合 Proxy 的典型应用场景 Proxy 是 ES6 引入的一种元编程特性。它允许创建一个代理对象来包装目标对象,并拦截对目标…