【C++】SLT——Vector详解

news/2024/12/27 10:10:40/

本片要分享的是关于STL中Vector的内容,Vector的内容于string非常相似,只要会使用string那么学习Vector时会非常流畅。

目录

1.vector介绍 

2.vector的简单实用

2.1.简单的无参构造

 ​编辑2.2.简单带参构造

2.3.迭代器区间初始化

2.4.vector的遍历

2.5.vector插入数据

2.6.扩容机制 

不同平台扩容机制

reverse

resize


1.vector介绍 

 官方的简介是vector是由一个动态增长数组实现的顺序容器,其实再简称一点就是顺序表。

以下是vector的组件

默认成员函数

 迭代器

与容量相关的函数

 与访问数据相关的函数

 与修改容器数据相关的

 可以看到上面有我们在string中就接触过的一些函数,比如push_back,下标访问时的operator[],测量长度的size,等等

所以这也是我们学习vector比较容易的原因,同时vector在设计上也基于string有了一些改进,在内部函数的设计方面也更加合理了一些;

2.vector的简单实用

2.1.简单的无参构造

我们上代码来观察,先从最最简单的初始化构造来开始

如上是一个vector的无参构造 

 首先我们需要包含vector的头文件

其次我们在定义的时候需要将容器实例化, 就是规定我们的数据类型;

 
2.2.简单带参构造

#include<iostream>
#include<vector>
using namespace std;
void test_vector1()
{vector<int> v1; vector<int> v2(10,0); 
}
int main()
{}

观察我们构造的v2,其中有两个参数,那这样的带参构造就是开辟是个空间,并且都初始化为0。

对比C语言我们不仅需要开一个数组,还需要memset,非常的麻烦;

2.3.迭代器区间初始化

#include<iostream>
#include<vector>
using namespace std;
void test_vector1()
{vector<int> v1; vector<int> v2(10,0); vector<int> v3(v2.begin(), v2.end());}
int main()
{test_vector1();return 0;
}

观察v3的初始化方式,我们使用了v2的迭代器的起始位置和末尾的位置

以上是相同容器的迭代器区间的初始化构造,那不同容器之间的初始化构造呢;

#include<iostream>
#include<vector>
using namespace std;
void test_vector1()
{vector<int> v1; vector<int> v2(10,0); vector<int> v3(v2.begin(), v2.end());string s("hello world");vector<int> v4(s.begin(), s.end());}
int main()
{test_vector1();return 0;
}

那当然也是可以的,可以看到我们在初始化v4的时候使用了字符串s的区间,也能完成初始化,但是我们需要注意的是这里的底层涉及到隐式类型转换,所以才能初始化成功。

2.4.vector的遍历

我们在上面的介绍中就可以看到vector读取数据时可以采用[],我们不妨将初始化后的v3进行遍历

void test_vector2()
{vector<int> v2(10, 0);vector<int> v3(v2.begin(), v2.end());for (size_t i = 0; i < v3.size(); i++){cout << v3[i] << ' ';}cout << endl;
}
int main()
{test_vector2();return 0;
}

以下 是输出结果

 可以看到我们使用v2迭代器区间初始化的v3输出的结果和我们想要的结果相同。

这里使用了for循环和[ ]对数据进行读取,还可以使用迭代器进行访问。

void test_vector2()
{vector<int> v2(10, 0);vector<int> v3(v2.begin(), v2.end());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;
}

同样的我们首先要在vector类中声明并定义迭代器it,将v3的begin的位置给it,在while循环中依次将it解引用并输出,再对it进行++迭代,此时就完成了迭代器的遍历;

 第一行的输出结果为for循环;第二行的结果为迭代器,他们都可以进行遍历;

在这里需要提醒大家的是迭代器中的begin或是end等等是指向数据的位置

 所以这里我们可以将迭代器的功能理解为指针,遍历时将其解引用即可得到数据。

2.5.vector插入数据

如下是涉及到修改内容的函数

首先是尾插(push_back)

void test_vector8()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (auto e : v){cout << e << ' ';}cout << endl;
}
int main()
{test_vector8();return 0;
}

 

结果不出所料,和我们在string中学到的插入方式相同;

同样的也有中间插入的方式insert, 

可以看到有很多种插入的方式,这里简单使用

 可以看到在begin 的位置之前插入了0;

那如何在以上数据的3的前面插入想要的数呢?

auto it = find(v.begin(), v.end(), 3);if (it != v.end());{v.insert(it, 30);}for (auto e : v){cout << e << ' ';}cout << endl;

这里我们就需要通过find来配合使用insert函数来查找并插入,结果如上;

2.6.扩容机制 

 

不同平台扩容机制

接下来是有关容量的函数

我们首先来研究vector的扩容机制;

在string中我们了解到可以插入很多数据时,系统会自动扩容,在vector中也同样如此;我们用代码来了解一下vector的扩容机制

void test_vector5()
{size_t sz;vector<int> v;sz = v.capacity();for (size_t i = 0; i < 100; i++){v.push_back(i);if (sz != v.capacity()){sz = v.capacity();cout << "capacity changed" << sz << endl;}}
}

可以看到我我们在循环中给v插入数据,如果v的最大容量和插满数据时相同,系统就会自动扩容,此时我们再改变容量,并且标识出容量已经改变,那此时运行结果会是怎样呢?

 我们可以看到大概是以原先容量的1.5倍进行扩容。

同样的代码我们在Linux系统下使用g++编译会有什么效果

 可以看到对比vs环境下的1.5倍扩容,g++使用的是二倍扩容

reverse

其中还有reserve函数,他的作用是开辟空间,还是如上代码,我们使用reserve尝试一下

void test_vector6()
{size_t sz;vector<int> v;v.reserve(100);sz = v.capacity();for (size_t i = 0; i < 100; i++){v.push_back(i);if (sz != v.capacity()){sz = v.capacity();cout << "capacity changed" << sz << endl;}}
}

我们在它扩容之前使用reserve函数提前开好空间,运行结果如下

 可以看到之前的扩容过程都不见了,原因是我们在扩容之前使用了reverse提前开了空间,将capacity修改成我们想要的,即可跳过在for循环中一边插入数据一边扩容的情况。

resize

resize不同于reserve的是,resize不仅可以改变capacity的大小,同时也可以改变size的大小,还是上段同样的代码,这里将reserve修改为resize来观察结果,

resize不仅可以修改容量的大小,还可以修改其本身的长度,这里的运行结果是在resize后的数据再进行插入,也就是说将两端数据接到一起。

还需要注意的一种情况如下

我们使用reserve直接开辟空间,然后直接去访问(利用for循环插入数据) reserve开辟的空间并打印是否可行呢?

结果是不行的,原因是这里访问v使用的是[ ],而在[ ]之前的模拟实现中,也就是它的底层逻辑是有assert断言的,条件是访问的下标必须小于size,而reserve只能修改capacity,不能修改size,所以就会报错。 

那使用resize即修改size也修改capacity会怎样呢?

 可以看到这样操作就很丝滑了。

以上就是本次要分享的内容,在vector中还有一些不常用的函数在这里没有深入分析到,还请感兴趣的同学们自行尝试,如果对你有所帮助还请多多三连支持,感谢您的阅读。


http://www.ppmy.cn/news/1073791.html

相关文章

什么是OLAP

一、什么是OLAP OLAP&#xff08;On-line Analytical Processing&#xff0c;联机分析处理&#xff09;是在基于数据仓库多维模型的基础上实现的面向分析的各类操作的集合。可以比较下其与传统的OLTP&#xff08;On-line Transaction Processing&#xff0c;联机事务处理&…

C++ 构造函数、析构函数调用虚函数

C虚函数是通过虚表实现的&#xff0c;虚函数的地址记录在需表中&#xff0c;只对象完成构造完成后&#xff0c;虚函数的地址才最终确定。 构造函数中调用虚函数 基类先于派生类构造&#xff0c;所以构造时没法调用到派生类的虚函数&#xff0c;也就是说只能调用到自己&#x…

universal robot 机械臂 官方基本教程

https://academy.universal-robots.cn/modules/e-Series-core-track/Chinese/module3/story_html5.html?courseId2166&languageChinese 教程1 控制箱内部 包含&#xff1a; 主机板&#xff0c;SD卡&#xff0c;和安全控制板 安全控制板负责所有控制信息&#xff0c;包括…

GiraffeDet助力yolov8暴涨分---有可执行源码

Yolov8魔改–加入GiraffeDet模型提高小目标效果 VX搜索晓理紫关注并回复有yolov8-GiraffeDet获取代码 [晓理紫] 1 GiraffeDet模型 GiraffeDet是一种新颖的粗颈范例&#xff0c;一种类似长颈鹿的网络&#xff0c;用于高效的目标检测。 GiraffeDet 使用极其轻量的主干和非常深且…

C语言二——依次将10个数输入,要求将其中最大的数输出

这是一个简单的C语言程序&#xff0c;它会接受用户输入的10个整数&#xff0c;然后找出最大值并输出。 程序的执行步骤如下&#xff1a; 声明一个数组 n&#xff0c;用于存储用户输入的10个整数&#xff0c;声明一个变量 i 和 t。提示用户输入10个数。使用 for 循环&#xff…

你觉得 Android 还有必要继续吗?

前言 这些年&#xff0c;总是听到有人说Android 开发岗位要凉了&#xff0c;不好做了。坦白说&#xff0c;市场倾向理性&#xff0c;竞争变强是很正常的事。但你发现总有些人&#xff0c;他们拿的 Offer 薪资是更高的&#xff0c;能达到年薪五六十万&#xff0c;甚至年薪百万。…

SpringBoot常用的简化开发注解

一、引言 在Spring Boot框架中&#xff0c;有许多常用的注解可用于开发项目。下面是其中一些常见的注解及其功能和属性的说明&#xff1a; 1、RestController RestController 是 Spring Framework 中的一个注解&#xff0c;用于标识一个类是 RESTful 服务的控制器。它结合了…

接口幂等性设计的最佳实现

一、什么是幂等 二、为什么需要幂等 三、接口超时了&#xff0c;到底如何处理&#xff1f; 四、如何设计幂等 全局的唯一性ID 幂等设计的基本流程 五、实现幂等的8种方案 selectinsert主键/唯一索引冲突 直接insert 主键/唯一索引冲突 状态机幂等 抽取防重表 token令牌 悲观锁…