【C++】详解vector二维数组的全部操作(超细图例解析!!!)

【C++】详解vector二维数组的全部操作(超细图例解析!!!)

目录

一、前言

二、 深度理解vector 的二维数组(重点!)

 三、vector 二维数组的空间理解(重点!)

✨问题分析

✨如何合理定制vector的内存空间

 四、vector 二维数组的初始化

五、vector 二维数组的 添加与删除

✨添加一行

✨添加一列

✨删除一行

✨删除一列

六、常考面试题

 七、共勉


一、前言

    最近在刷 Leetcode 的时候,发现 vector 的二维数组操作 都还没弄明白吗,但是STL的强大是众所周知滴,早晚都是要解决滴,因此专门写下这篇文章,以供自己复习和各位老铁使用,快速的回忆vector的用法,让你找回自信,不用再竞赛的时候颜面尽失。
    vector 的一维操作可以看看之前这篇文章哦:vector 详解

二、 深度理解vector 的二维数组(重点!)

     在解决大部分算法问题的时候,通常都会遇到二维数组 vector<vector<int>> table, 但是不知道怎么对其进行初始化(初始化时指定二维容器的大小),于是通过查阅了很多资料,将其总结如下:
vector<vector<int>> table(size1, vector<int>(size2, 0)); 

 代码说明:声明一个名为 table 的容器,其元素为 vector的容器。简单来说类似一个int型的二维数组。

这样,就得到了一个如下图所示的二维容器。 

 具体代码的内容,可以这样理解:

 图中,我将外围容器table的初始化参数分成了两部分 A、B 

  • A: table外围容器的大小
  • B: table外围容器的内容,即 size1个vector型的元素。
  • B1:内部容器的大小
  • B2:内部容器的内容
观察规律,可以得出如下的初始化格式:容器(大小,内容)

 三、vector 二维数组的空间理解(重点!)

      我们都知道,在 C语言 中,创建一维数组或者更高维度的数组时,都是需要提前给他分配大小的。
      而在 C++的 vector 容器 中我们并不需要那么做,我们可以直接push进去后,根据下标访问它,如:

 ✨问题分析

 vector<int> a; a.push_back(1); cout << a[0]; 

 由此处诞生出了两个问题

  1.  在处理小数据是没问题的,但处理大数据时,vector 会重新分配内存,一般会把容量(所分配好的内存空间)翻倍,这将导致出现大量的冗余空间。
  2. 在对二维的数组创建时,会出现创造失败的情况,如下面的情况就会报错:
vector<vector<int>> a; // 创建一个空的二维向量a a[0].push_back(1); // 尝试访问a的第一个元素(即空向量),然后在其上调用push_back()方法,但是a目前为空,没有索引为0的元素,因此这将导致访问越界错误。 cout << a[0][0]; // 试图输出a的第一个元素的第一个元素,但是由于a为空,这也会导致访问越界错误。 

错误原因: 

  1. 尝试访问 a 的第一个元素(即空向量),然后在其上调用push_back()方法,但是a目前为空,没有索引为 0 的元素,因此这将导致访问越界错误。
  2.  试图输出 a 的第一个元素的第一个元素,但是由于a为空,这也会导致访问越界错误。

✨如何合理定制vector的内存空间

首先要明白,我们第二个问题的出现,其实就是因为第一个问题,那么我们逐个分析一下:
  • 对于 vector 的 .size() 代表查询它的 动态数组vector中有多少个有效数。
  • 对于 vector 的.capacity()代表查询它的容量(最多放多少个数)。
 如何理解这两个函数接口呢?
  • resize(Container::size_type n)强制把容器改为容纳n个元素。调用resize之后,size将会返回n。如果n小于当前大小,容器尾部的元素会被销毁。如果n大于当前大小,新默认构造的元素会添加到容器尾部。如果n大于当前容量,在元素加入之前会发生重新分配。
  • reserve(Container::size_type n)强制容器把它的容量改为至少n,提供的n不小于当前大小。这一般强迫进行一次重新分配,因为容量需要增加。(如果n小于当前容量,vector忽略它,这个调用什么都不做,string可能把它的容量减少为size()和n中大的数,但string的大小没有改变。
 【总结】上述两方法的区别
  1. reserve表示容器预留空间,但并不是真正的创建对象,需要通过insert()或push_back()等创建对象resizee既分配了空间,也创建了对象
  2. reserve只修改capacity大小,不修改size大小,resize既修改capacity大小,也修改size大小。
  3. resize带两个参数,一个表示容器大小,一个表示初始值(默认为0)。reserve只带一个参数,表示容器预留的大小。
  4. 因此,我们在对一维数组push前,可以来一个reverse,这样在不断push的过程中就不会发生重新分配了。如:vector<int> a; a.reserve(1000);
所以针对问题二出现的原因:vector 直接根据下标访问必须要先push,存在数才行。而上面的代码想直接对第一行里面的各个元素进行访问或者修改时绝对不行的。但是相反,如果我们先对第一行进行赋值,然后再访问,这样又是可以的,如:
vector<vector<int>> a; a.push_back(vector<int>()); // 添加一个空的一维向量 a[0].push_back(1); // 现在可以向a的第一个元素(现在是一个向量)添加元素了 cout << a[0][0]; // 输出1 

 因此,想要直接对第一行第一列的进行调整,就需要我们预先给他点空间了!!

 四、vector 二维数组的初始化

首先,要先知道:二维 vector 如何获得行数和列数。
vector<vector<int>> a(r, vector<int>(c)); int row = a.size(); //获取行数 int column = a[0].size(); //获取列数 

 方法一:定义时,直接初始化
(1)下面定义的是行为r,列为c的二维数组

vector<vector<int>> ans(r, vector<int>(c)); 

(2)下面定义的是行为r,列为c的二维数组,初始值为0

vector< vector<int> > a(r, vector<int>(c, 0)); 

方法二:用resize来提前构建

(下面定义的是行为r,列为c的二维数组,初始值为0–因为resize默认为0)

vector<vector<int>> new_mat(r);//注意这个r是不可缺少的,规定其有多少行 for(int i=0 ;i<r; i++) //二维vector的初始化时有要求的 { new_mat[i].resize(c); } 

方法三:每行不一定几个数,就是想对每行的列进行操作

vector<vector<int>>mat(r);//每行的定义 mat[i].push_back(1);//这就是该第i-1行的插入一个元素,值为1 

 

五、vector 二维数组的 添加与删除

✨添加一行

//插入一行数组:将in_row数组插入到第2行! vector<int> in_row(5,6);//初始化一个数组,包含5个元素并且全为6 a.insert(a.begin()+2,in_row);

✨添加一列

for(int i=0;i<a.size();i++) { a[i].insert(a[i].begin()+2,9); }

✨删除一行

a.erase(a.begin() + 2, a.begin() + 3);

✨删除一列

//删除a的第二列 for (int i = 0; i < a.size(); i++) { a[i].erase(a[i].begin() + 2, a[i].begin() + 3); }

六、常考面试题

题目:杨辉三角形
链接:118. 杨辉三角
class Solution { public: vector<vector<int>> generate(int numRows) { // 生成一个二维数组 vector<vector<int>> vv; // 给二维数组开辟有效空间---开辟numRows行 vv.resize(numRows); for(int i = 0;i<numRows;i++) { //每一行开辟i+1个 空间,并且进行初始化为 0 vv[i].resize(i+1,0); //每一行的第一个和最后一个为 1 vv[i].front() = vv[i].back() = 1; } // 每一次都从第3行开始,第二个开始遍历 for(int i = 2;i<numRows;i++) { for(int j = 1;j<i;j++) { vv[i][j] = vv[i-1][j-1] + vv[i-1][j]; } } return vv; } };

 七、共勉

 以下就是我对【C++ STL】vector 二维数组的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对C++STL库的理解,请持续关注我哦!!!

Read more

Flutter 三方库 changelog_cli 的鸿蒙化适配指南 - 自动化生成 CHANGELOG、标准化版本管理与工程化协作利器

Flutter 三方库 changelog_cli 的鸿蒙化适配指南 - 自动化生成 CHANGELOG、标准化版本管理与工程化协作利器

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 changelog_cli 的鸿蒙化适配指南 - 自动化生成 CHANGELOG、标准化版本管理与工程化协作利器 前言 在 Flutter for OpenHarmony 的企业级开发流程中,维护一份详实、规范的更新日志(CHANGELOG)是版本控制的核心环节。changelog_cli 是一个专为 Flutter 开发者设计的命令行工具,它能够基于特定的规范自动生成或更新日志。本文将探讨如何将该工具集成到鸿蒙项目的开发流水线中,大幅提升工程化协作效率。 一、原理解析 / 概念介绍 1.1 基础原理 changelog_cli 通过读取项目的 pubspec.yaml 版本信息和特定的配置文件,配合开发者在命令行输入的更新内容,自动拼装成符合 Keep a Changelog 规范的

By Ne0inhk
中小团队如何低成本搭建项目管理系统?基于 Ubuntu 的 Dootask 私有化部署实战

中小团队如何低成本搭建项目管理系统?基于 Ubuntu 的 Dootask 私有化部署实战

作为技术负责人或者创业团队的 Team Leader,你是否也经历过这样的“项目管理噩梦”? 团队规模刚过 10 人,管理瞬间失控。需求变了没记录,Bug 修复进度全靠吼,代码上线版本混乱。老板让你上一套项目管理系统,你调研了一圈发现:Jira 太贵且对非技术人员极不友好;禅道功能强大但界面由于年代久远,操作逻辑繁琐,推行下去阻力巨大,运营和设计同事天天抱怨学不会;市面上的 SaaS 工具(如 Teambition)虽然好用,但核心数据存在别人云端,想要二次开发或私有化部署,授权费又是一笔不小的开支。 这其实是很多中小团队的共性痛点:需要一个好用的开源项目管理工具,既要免费开源、数据私有化,又要界面现代、部署简单。 为了帮大家理清思路,我画了一张当前团队协作常见困境的思维导图,看看你是否中招了: 最近在为团队寻找替代方案时,我在 GitHub 上发现了一个宝藏项目——DooTask。目前它在 GitHub 上已经获得了 4k+ Star,这不仅代表了社区认可度,

By Ne0inhk

Flutter 组件 rexios_lints 适配鸿蒙 HarmonyOS 实战:代码工艺化治理,构建编译期的架构合规防线

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 rexios_lints 适配鸿蒙 HarmonyOS 实战:代码工艺化治理,构建编译期的架构合规防线 前言 在鸿蒙(OpenHarmony)生态迈向大规模团队协同、涉及分布式跨端开发与高频业务迭代的背景下,如何确保代码质量的底线、统一多人的编程风格并拦截潜在的运行时陷阱,已成为决定项目长效生命力的“基础设施”。在鸿蒙设备这类对应用稳定性与资源占用有严苛要求的环境下,如果缺乏强力的静态代码分析(Lints)约束,由于由于开发者习惯差异导致的异步坑洞、内存泄漏或命名碎片化,将直接侵蚀鸿蒙系统的运行流畅度。 我们需要一种能够超越官方默认规则、具备“架构审判”级别严密度且可高度定制的静态分析套件。 rexios_lints 为 Flutter 开发者提供了一套极其严苛且符合现代工程实践的 Lint 规则集。它不仅涵盖了基础的代码格式校验,更深入到异步编程(Future/Stream)安全、强类型检查等核心架构领域。在适配到鸿蒙 Harmon

By Ne0inhk
Flutter 三方库 bybit 的鸿蒙化适配指南 - 实现高性能交易数据获取、支持 WebSockets 实时订单簿与加密货币交易接口集成

Flutter 三方库 bybit 的鸿蒙化适配指南 - 实现高性能交易数据获取、支持 WebSockets 实时订单簿与加密货币交易接口集成

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 bybit 的鸿蒙化适配指南 - 实现高性能交易数据获取、支持 WebSockets 实时订单簿与加密货币交易接口集成 前言 在进行 Flutter for OpenHarmony 的金融科技(FinTech)应用开发时,对接主流交易所的实时数据和交易功能是核心需求。bybit 是一个专为 Bybit 交易所设计的异步 Dart SDK。它封装了 REST API 调用和复杂的 WebSockets 订阅逻辑。本文将探讨如何在鸿蒙系统下构建低延迟、高可靠的加密资产交易终端。 一、原原理分析 / 概念介绍 1.1 基础原理 bybit 库基于 http 处理基础请求,并利用 web_socket_

By Ne0inhk