【STL专题】深入探索vector:动态数组的魔力【入门指南】

news2024/11/22 18:20:15

 欢迎来到 CILMY23 的博客

🏆本篇主题为:深入探索vector:动态数组的魔力,入门指南

🏆个人主页:CILMY23-CSDN博客

🏆系列专栏:Python | C++ | C语言 | 数据结构与算法 | 贪心算法 | Linux | 算法专题 | 代码训练营

🏆感谢观看,支持的可以给个一键三连,点赞收藏+评论。如果你觉得有帮助,还可以点点关注


前言

在模拟实现完string后,才明白大家为什么都在吐槽string,甚至阅读了一篇大佬的发言

STL 的string类怎么啦?_string类在stl里面吗-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/haoel/article/details/1491219

string 的接口繁多,初次学习的时候眼花缭乱,不禁感叹的是,我也写下了最长的一篇博客(链接)。记得写了好几天。

甚至还阅读了一篇好文

C++面试中string类的一种正确写法 | 酷 壳 - CoolShellicon-default.png?t=N7T8https://coolshell.cn/articles/10478.html这几篇对加深string都有认识,那接下来我们将接触vector容器,作为经典的容器之一,它又会带给我们什么呢?我们接着往下看。

提示:本篇附赠了没有学过string想直接上手的入门指南


vector

一、vector介绍

 二、vector的详解

💫vector的接口 

💫vector原型 

💫vector 的默认成员函数 

🍃构造函数(⭐)

🍃析构函数

🍃赋值运算符重载 

 💫vector 的遍历

💫vector 的扩容机制

💫vector 的对象操作

 💫vector 中的vector

 💫vector 中的对象数组

三、入门指南

💦vector对象创建

💦vector的插入

🍀尾插

🍀任意位置插入

 💦vector的常用接口

💦vector的删除

 🍀指定位置删除

 🍀尾删

💦vector的resize()和reserve()

🍀resize() 

🍀reserve() 


vector

一、vector介绍

vector文档: 

cplusplus.com/reference/vector/vector/icon-default.png?t=N7T8https://cplusplus.com/reference/vector/vector/文档当中的介绍我就不像string一样放截图翻译了,说的几点我直接翻译。

  1. 1.vector是一个顺序(序列)容器,它的表现形式是像可以改变大小(长度)数组一样。文档的第一句话就告诉我们vector是表示可变大小数组的序列容器。
  2. 文档的第二段话:就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理
  3. 文档的第三段在说vector的本质,它是利用动态数组实现的:本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小 为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是 一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
  4. 这一段是再说vector的空间是如何分配的:相对的,vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
  5. .因此,和数组相比,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
  6. 与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末 尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list 统一的迭代器和引用更好。

 二、vector的详解

💫vector的接口 

 vector的接口比起string就没有那么多了,大致接口如下,我们可以看到我们的老伙伴了,构造函数,析构函数,size,还有[]。接下来我们从成员函数开始,一步步学习如何使用吧。

💫vector原型 

vector原型如下,第一个参数,class T是一个模板,而第二个是空间配置器,也就是是内存池,所有容器都用内存池来开空间,这样可以提高效率。我们只需要知道,它是用来分配内存即可。 

💫vector 的默认成员函数 

🍃构造函数(⭐)

  cplusplus.com/reference/vector/vector/vector/

进入构造函数的文档界面,我们看到有四个构造函数,其中重点掌握的,也是最常用的,我在图片中已经标出来了。剩下的了解就差不多了。

第一个是默认的构造函数,是无参的,那括号中的又是什么呢?

const allocator_type& alloc = allocator_type() 

 这个是我们刚刚提到的内存分配,所以不用太在意这一块,之后我们总会接触到的。

第一个无参构造函数,也是我们很经常用的,除此之外还可以使用第四个拷贝构造函数。

使用如下,这一块和string是差不多的。 

🍃析构函数

对析构函数我们不必关注太多,稍微看看就行,在学习的时候,我们知道析构函数的功能即可 .

 

🍃赋值运算符重载 

赋值运算符重载,就给了一种形式, 

 其实际操作如下:

这个应用起来,可比string的文档少的多。

 💫vector 的遍历

vector 的遍历和string 是一样的,大家都可以用迭代器,下标加[],以及范围for三种形式。 

实际操作:

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

vector<int>::iterator it = v3.begin();
while (it != v3.end())
{
	cout << *it << " ";
	++it;
}
cout << endl;

for (auto e : v3)
{
	cout << e << " ";
}
cout << endl;

当然因为我们还没有插入任何数据,所以是看不到屏幕上的情况的。 我们可以对v1进行push_back一些数据。

然后就可以显示了。 

💫vector 的扩容机制

听说VS下的vector扩容和g++的不一样,我们来试试就知道了。

// 测试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的2倍扩容。

capacity的代码在vs和g++下分别运行会发现,vs下capacity是按1.5倍增长的,g++是按2倍增长的。 这个问题经常会出现,不要固化的认为,vector增容都是2倍,具体增长多少是根据具体的需求定义的。vs是PJ版本STL,g++是SGI版本STL。

💫vector 的对象操作

是否大家记得在我们写string的时候,提到过find函数,如图所示,

 但是vector的介绍这里面没有find,它居然写在算法里面了。

这是算法库的文档 

- C++ Reference (cplusplus.com)icon-default.png?t=N7T8https://legacy.cplusplus.com/reference/algorithm/?kw=algorithm 我们可以找到这个find函数。

 我们还可以通过文档查看value,这段话是说,如果找到了,返回下标,没找到就返回last。这个last 实际上就是我们给的的区间末尾。

 所以具体的使用如下:

 为什么vector用算法里面的find,而string要用自己的find?

原因可能有以下三点:

1.string写的早

2.string还要支持字串的查找

3.vector只需要找某个值

 💫vector 中的vector

 以前我们在学习C语言的时候,接触过一个二维数组,我们说二维数组可以看过由一维数组构成的。

 我们可以通过一串代码来理解一下vector中的二维表现形式。

void test1()
{
	vector<vector<int>> vv;

	// 初始化
	vv = { {1, 2, 3},
		  {4, 5, 6},
		  {7, 8, 9} };

	// 访问二维矩阵的元素
	cout << "vv[0][1]: " << vv[0][1] << endl; 
	cout << "vv[2][2]: " << vv[2][2] << endl;  
}

解析:

当我们声明 vector<vector<int>> vv; 时,我们创建了一个  vector 对象 vv,其中每个元素也是一个 vector<int> 对象。这种嵌套的结构可以被看作是二维数组。

 

在这个二维数组中,每个元素 vv[i] 也是一个 vector<int> 对象,表示二维数组的一维数组。

 

我们可以使用下标来访问和操作这个二维数组。

例如,可以使用 vv[i][j] 来访问二维数组中的特定元素,其中 i 表示行下标,j 表示列下标。

就是按二维数组的方式去理解即可,但是又不一样,这个毕竟中间不一定只存vector。结构体中嵌套一个结构体,实际上用指针模拟实现二维数组的时候也可以这么看。

画图理解:

这里因为是整形类型,所以我写的是int* 的指针,当然实际情况可能并不这样,我们只是大概的去类比一下,稍微画画,理解这个二维vector这个概念。 

 💫vector 中的对象数组

 像上一个小节中的,二维vector其实是一个对象数组的概念。

"vector的对象数组"指的是将多个对象存储在一个 vector 容器中,形成一个对象数组的结构。

在C++中,vector 是一个动态数组容器,可以存储多个对象,并且可以根据需要动态调整大小。每个对象可以是相同类型的,也可以是不同类型的。

当我们将多个对象存储在 vector 中时,就形成了一个对象数组。这个对象数组可以根据需要进行扩展或缩小,并且可以使用下标来访问和操作其中的对象。

三、入门指南

记得在使用 vector 之前包含 <vector> 头文件。 

💦vector对象创建

vector<type> name

其中,type 是你要存储在 vector 中的对象的类型,而 name 是你给这个 vector 对象起的名称。例如,如果你想创建一个存储整数的 vector 对象,你可以这样写:

vector<int> v

同样,如果你想创建一个存储字符串的 vector 对象,你可以这样写:

vector<string> names

这将创建一个名为 names 的 vector 对象,用于存储字符串类型的数据。

你可以根据需要在程序中创建多个 vector 对象,并使用它们来存储和操作不同类型的数据。

💦vector的插入

🍀尾插

要向 vector 中进行尾插操作,可以使用 push_back() 函数。这个函数将一个元素添加到 vector 的末尾。

vector<int> numbers;

// 进行尾插操作
numbers.push_back(1);
numbers.push_back(2);
numbers.push_back(3);

运行这段代码,输出将会是 1 2 3。

🍀任意位置插入

 要向 vector 中任意插入元素,可以使用 insert() 函数。

insert() 函数有多种用法,可以在指定位置插入一个元素,也可以在指定位置插入一个范围内的元素。

在指定位置插入一个元素:

vector<int> v = {1, 2, 3, 4, 5};

// 在位置为 index 的位置插入元素 6
v.insert(v.begin() + index, 6);

在指定位置插入一个范围内的元素:

vector<int> v1 = {1, 2, 3};
vector<int> v2 = {4, 5};

// 在位置为 index 的位置插入 v2 中的元素
v1.insert(v1.begin() + index, v2.begin(), v2.end());

 💦vector的常用接口

在 C++ 中,vector 提供了一些常用接口,一起来看看吧。

vector<int> v;

v.size();//返回容器中元素个数
v.begin()//返回头部迭代器
v.end()//返回尾部+1迭代器
v.empty()//判断是否为空
  • v.size():返回 vector<int> 容器中的元素个数。它返回一个无符号整数类型的值,表示容器中元素的数量。
  • v.begin():返回一个指向 vector<int> 容器中第一个元素的迭代器。它指向容器的起始位置。
  • v.end():返回一个指向 vector<int> 容器末尾元素的下一个位置的迭代器。它指向容器的结束位置。
  • v.empty():检查 vector<int> 容器是否为空。如果容器为空,则返回 true;否则返回 false。 

💦vector的删除

要从 vector 中删除元素,可以使用 erase() 或 pop_back() 函数。 

 🍀指定位置删除

使用 erase() 函数删除指定位置的元素:

vector<int> v = {1, 2, 3, 4, 5}; //这是C++11的写法

// 删除位置为 index 的元素
v.erase(v.begin() + index);

 🍀尾删

vector<int> v = {1, 2, 3, 4, 5};

// 删除最后一个元素
v.pop_back();

💦vector的resize()和reserve()

resize() 和 reserve() 是 vector 类提供的两个函数,用于调整容器的大小和预分配内存空间。

🍀resize() 

resize() 函数用于调整 vector 的大小,可以增加或减少元素的数量。

vector<int> v = {1, 2, 3};

// 增加容器的大小为 5,新增的元素用默认值填充
v.resize(5);

// 减少容器的大小为 2,多余的元素将被删除
v.resize(2);

在上面的代码中,resize() 函数接受一个整数参数,表示要调整的大小。如果调整后的大小比当前大小大,则新增的元素将用默认值填充;如果调整后的大小比当前大小小,则多余的元素将被删除。

🍀reserve() 

reserve() 函数用于预分配 vector 的内存空间,以提高性能。

vector<int> v;

// 预分配至少能容纳 100 个元素的内存空间
v.reserve(100);

在上面的代码中,reserve() 函数接受一个整数参数,表示要预分配的内存空间大小。这样做可以避免频繁的内存重新分配,提高 vector 的性能。

需要注意的是,resize() 和 reserve() 函数都会影响 vector 的大小和容量。大小是指容器中实际存储的元素数量,而容量是指容器当前分配的内存空间大小。


🛎️感谢各位同伴的支持,本期C++专题就讲解到这啦,下期我们将进入模拟实现vector,如果你觉得写的不错的话,可以给个一键三连,点赞,收藏+评论,可以的话还希望点点关注,若有不足,欢迎各位在评论区讨论。     

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

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

相关文章

结构体指针数组函数综合应用改写选票系统

第一次写百行的代码 有点吃不消 感受到程序员的不容易 其中遇到了很多问题 希望分享给大家 下面是是完整的且完善的代码 #include<stdio.h> #include<string.h> #include <stdlib.h> //定义结构体 struct XuanMin {char name[32];int tickets; }; //指针函…

1-4章节复习总结

1-4章节总结 章节重点回顾-第一章-中央处理单元练习题 章节重点回顾-第一章-进制章节重点回顾-第一章-校验码奇偶校验码CRC循环冗余校验码海明码练习题 多草节重点回顾-第一草-计算机体系结构分类章节重点回顾-第一章-计算机指令练习题 章节重点回顾-第一章-指令流水线练习题 章…

​​​​​Tomcat部署及优化

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

洞见新能源汽车产业更智能的未来

新能源汽车行业进入智能化时代&#xff0c;除了备受关注的无人驾驶领域&#xff0c;新能源汽车在智能化的进程逐渐加快。智能化已成为中国汽车品牌的竞争力。 作为专业提供算网的服务商之一&#xff0c;VERYCLOUD睿鸿股份跟随新能源汽车行业快速变化&#xff0c;受邀前往CIAS 2…

天环公益首次推出原创开发进度网站,配备后台管理系统

天环公益组织近期创新性地发布了一个专用于监控与展示项目开发进程的官方网站&#xff0c;该网站特色在于其自研的后台管理系统。 对于有兴趣深入了解或参与管理的用户&#xff0c;可直接访问后台页面&#xff0c;入口为&#xff1a;admin.php。 值得注意的是&#xff0c;当前…

教育教学质量评测系统开发之软件技术分析

开发教学质量评测系统它不仅能够有效提升教育管理的科学性与透明度&#xff0c;还能精准反映教学过程中的问题与亮点&#xff0c;为教育决策提供坚实的数据支持。通过该系统&#xff0c;学校能够全面、客观地收集学生、教师及家长的反馈意见&#xff0c;促进教学相长&#xff0…

java各种锁有什么区别

Java 虚拟机&#xff08;JVM&#xff09;中有几种不同类型的锁&#xff0c;每种锁都有其特定的用途和性能特点。下面我将为你介绍几种常见的锁&#xff1a; 1.独占锁&#xff08;也称为悲观锁&#xff09;&#xff1a; 1.synchronized&#xff1a;这是 Java 提供的一种内置的独…

【数据结构】——栈和队列的实现(赋源码)

在前面我们已经学过顺序表以及单链表、双向表链的实现都是一种线性表&#xff0c;这里可以我们介绍栈和队列——是具有特殊化的线性表 栈 栈的概念以及结构 栈&#xff1a;⼀种特殊的线性表&#xff0c;其只允许在固定的⼀端进⾏插入和删除元素操作。进⾏数据插⼊和删除操作的…

Docker镜像的手动制作commit

目录 一、docker镜像说明 1.1 Docker镜像中有没有内核 1.2 为什么没有内核 1.3 容器中的程序后台运行会导致此容器启动后立即退出 1.4 Docker镜像的生命周期 1.5 制作镜像方式 二、 将现有容器通过docker commit手动构建镜像 2.1 基于容器手动制作镜像步骤 2.2 实战案…

【卷积神经网络】池化层【计算和python代码】

文章目录 1、简介2、池化层计算3、Stride4、Padding5、多通道池化计算6、数学公式⭐7、PyTorch 池化 API 使用7.1、形状调整7.2、最大和平均池化7.3、调整stride步长7.4、padding填充7.5、多通道池化7.6、完整代码⭐ 8、小结 &#x1f343;作者介绍&#xff1a;双非本科大三网络…

[Docker][Docker NetWork][上]详细讲解

目录 1.为什么需要网络管理2.Docker 网络架构简介0.铺垫说明1.CNM2.Libnetwork3.驱动 3.常见网络类型1.bridge 网络2.host 网络3.container 网络4.none 网络5.overlay 网络 1.为什么需要网络管理 容器的网络默认与宿主机及其他容器都是相互隔离&#xff0c; 但同时也要考虑以下…

Node污染 (Node.js)

&#x1f3bc;个人主页&#xff1a;金灰 &#x1f60e;作者简介:一名简单的大一学生;易编橙终身成长社群的嘉宾.✨ 专注网络空间安全服务,期待与您的交流分享~ 感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持&#xff01;❤️ &#x1f34a;易编橙终身成长社群&#…

C语言指针(Pointer)

指针与底层硬件联系紧密&#xff0c;使用指针可操作数据的地址&#xff0c;实现数据的间接访问 问题&#xff1a;这好好的一个变量&#xff0c;我定义完之后为啥不用它名字直接访问呢&#xff1f;我非要用间接访问&#xff0c;这不没事找事吗&#xff1f; 为什么需要指针? …

18.C语言函数相关练习题2

函数相关练习题2 1.不同班级的平均分2.二维数组和函数的概念3.外部变量和全局变量4.全局变量的例子5.输入10个数&#xff0c;找出最大数及最大数的下标 1.不同班级的平均分 #include <stdio.h>void inityarry(int arr[],int len){int i;for(i0;i<len;i){printf("…

【第八天】DNS及其查询过程

DNS及其查询过程 什么是DNS&#xff1f; 一般我们的主机&#xff0c;服务器都有一个ip地址&#xff0c;例如10.10.10.1。在计算机层面&#xff0c;如果我们要发送请求的话&#xff0c;首先就要知道我们的目标&#xff0c;也就是对方的ip地址。而IP地址很难记&#xff0c;比如…

初学者编程指南:方法与资源推荐

一、引言 编程已成为当代大学生的必备技能&#xff0c;但面对众多编程语言和学习资源&#xff0c;新生们常常感到迷茫。如何选择适合自己的编程语言&#xff1f;如何制定有效的学习计划&#xff1f;如何避免常见的学习陷阱&#xff1f;编程不仅是技术领域的一项基本技能&#…

H.264编码中的16x16宏块分析

&#x1f60e; 作者介绍&#xff1a;欢迎来到我的主页&#x1f448;&#xff0c;我是程序员行者孙&#xff0c;一个热爱分享技术的制能工人。计算机本硕&#xff0c;人工制能研究生。公众号&#xff1a;AI Sun&#xff08;领取大厂面经等资料&#xff09;&#xff0c;欢迎加我的…

快速索引alarm添加

快速索引alarm添加 添加预警alarm 文件夹和 temp_led.c , temp_led.h , humi_led.c, humi_led.h (1)点击品字, 添加alarm, 然后增加文件, 点进Source文件夹 (2)点击新建文件夹, 然后新建alarm文件夹 (3)把文件类型切换为all, 方便后续右键添加上述四个文件名字. (4)空白处, 右…