十一、vector 类

Ⅰ . vector 的介绍和使用

01 vector 的介绍

vector 的文档介绍:vector

① vector 是表示可变大小数组的序列容器,既像数组,又不像数组

像体现在:同样采用连续存储空间存储元素,可以使用下标访问元素

不像体现在:大小是可以动态改变的

② 本质上来说,vector 使用动态分配数组来存储它的元素

当新元素插入时,为了增加存储空间,这个数组就需要被重新分配大小。具体做法是分配一个新的数组,然后将全部元素转移到这个新的数组。就时间而言,这是一个相对代价较高的任务,因为每当一个新的元素加入后,vector 并不会每次都重新分配大小。

③ vector 分配空间策略:vector 会分配一些额外的空间以适应可能的增长,因此存储空间会比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于末尾插入一个元素时是在常数时间的复杂度完成的。

因此,vector 占用了更多的存储空间,为了获得管理存储空间的能力,并且有一种有效的方式去动态增长。

④ 与其他动态序列容器相比:

vector 在访问元素时更加高效,末尾添加和删除元素相对高效

但是对于其他位置不在末尾的插入和删除操作,效率更低

vector 的底层是一个动态的顺序表

02 vector 的初始化

#include <vector>
using namespace std;   

① 无参构造:

vector<int> v1;   // 无参构造,创建一个int类型的,空的vector对象

② 构造并初始化:

vector<int> v2(10, 1);   // 10个1

③ 迭代器区间初始化:

vector<int> v3(v2.begin(), v2.end());

④ 拷贝构造:

vector<int> v4(v2);

还可以不全部拷贝:

vector<int> v3(++v2.begin(), --v2.end());

对于迭代器区间初始化,它这里的 InputInerator 不一定是 vector Inerator。

它是一个模板,所以你传的是谁的迭代器,它就可以实例化出谁的迭代器

有时候我们可以这样初始化:

string s("hello world");
vector<char> v5(s.begin(), s.end());

03 调试观察

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

具体如下:

04 string 和 vector 的区别

string 和 vector 有什么区别呢?刚才通过监视观察,感觉 vector char 已经很像 string 了。

能不能让 vector char 去替代 string 呢?这合适吗?

答案是不能,因为 vector char 没有 \0 ,而 string 结尾有 \0

那我直接给 vector char 后面手动装一个 \0 行嘛?

你要硬是想这么玩,也不是不可以

但他们两个体系不一样,vector 是顺序表,存的是任意类型,是针对可动态增长的数组的。

而 string 就只是字符串,我随便举两个例子:

① vector 支持正常的增删查改,但是不支持 += (本身也没必要+=),也不支持比较大小。

② vector 也没有 c_str 这些东西,因为 string 作为字符串专用的类,能提供专有的接口(比如 +=,find),所以这就是 string 存在的意义。

05 关于 vector 的析构、拷贝构造和赋值构造

至于析构函数,一般情况下我们不需要管,因为它会自动调用。

拷贝构造和赋值构造,vector 的拷贝构造和赋值其实就是深拷贝。

这些我们放在 vector 模拟实现的章节里详细探讨。

Ⅱ . vector 的遍历

01 push_back()

vector 不能使用 operator+= 

string 能用 += 主要是 string 不仅可以尾插一个字符还可以追加一个字符串。

但是 vector 就只支持一个一个数据的插入和删除,push_back 和 pop_back

我们发现,vector 和 string 一样,是没有提供 push_front 和 pop_front 的,因为挪动数据效率低。

如果你硬是要去头插头删,可以用 insert 和 erase 去操作

举个例子:

void vector_Traversal_test() {vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);
}

02 下标 + 方括号遍历

vector 是连续的空间,又支持 operator[] 和 size() ,所以可以用下标+方括号遍历。

看代码:

void vector_Traversal_test() 
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);// 遍历for (size_t i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;
}

运行结果如下:

当然也可以修改:

void vector_Traversal_test() 
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);// 遍历for (size_t i = 0; i < v.size(); i++){v[i] += 1;cout << v[i] << " ";}cout << endl;
}

运行结果如下:

03 访问 vector 的 at()

at() 和 operator[] 一样,也是用来访问 vector 的,但是 at() 会进行边界检查。

代码演示:

void vector_test2()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);cout << v.at(0) << endl;cout << v.at(3) << endl;
}

运行结果如下:

注意:operator[] 会断言检查越界,at() 会抛异常

void vector_test2()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);cout << v.at(0) << endl;cout << v.at(3) << endl;cout << v.at(4) << endl;
}

04 使用迭代器遍历

代码演示:

void vector_Traversal_test() 
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it = v.begin();while (it != v.end()){*it -= 1;cout << *it << " ";it++;}cout << endl;
}

运行结果如下:

05 范围 for

vector 支持迭代器,也就支持范围 for,这个我们在模拟实现 string 的时候已经验证过了。

范围 for 的本质就是编译器在编译时自动替换成迭代器,这里也一样。

代码演示:

void vector_Traversal_test() 
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);// 范围forfor (auto e : v){cout << e << " ";}cout << endl;for (auto& e : v){e += 10;cout << e << " ";}cout << endl;
}

运行结果如下:

Ⅲ . vector 空间

01 获取数据个数的 size()

void vector_test3() 
{vector<int> v(6, 6);        // 生成6个6cout << v.size() << endl;
}

运行结果如下:

02 获取 vector 最大存储的 max_size()

void vector_test4()
{vector<int> v(6, 6);        cout << v.max_size() << endl;
}

运行结果如下:

03 改变 vector 容量的 reserve()

void vector_test5()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.reserve(100);
}

调试结果如下:仅扩容

reserve 会扩容,但是不会影响数据个数。[capacity] 4  → [capacity]100

04 改变 vector 大小的 resize()

void vector_test6()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.resize(100);
}

调试结果如下:扩容 + 初始化

string 的 resize 如果不指定 "填充值" ,默认给的是 \0

而 vector 的 resize 如果不指定,默认给的是其对应类型的缺省值作为 "填充值"

这里是 int 就是 0,如果是指针,对应的缺省值就是空指针。

提供特定的值:

void vector_test6()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.resize(100, 1);
}

调试结果如下:

注意:如果开的数据比之前更小,还会删除数据!

void vector_test6()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.resize(2);
}

调试结果如下:

这里虽然大小变成 2,数据也只有 [0]1 和 [1]2 了,但是容量仍然为 4

05 vector 空间增长问题

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

② reserve 只负责开辟空间,如果确定知道需要用多少空间,reserve 可以缓解 vector 增容的代价缺陷问题。

③ resize 在开空间的同时还会进行初始化,影响 size

测试:

// vector::capacity
#include <iostream>
#include <vector>int main()
{size_t sz;std::vector<int> foo;sz = foo.capacity();std::cout << "making foo grow:\n";for (int i = 0; i < 100; ++i) {foo.push_back(i);if (sz != foo.capacity()) {sz = foo.capacity();std::cout << "capacity changed: " << sz << '\n';}}
}

 VS运行结果如下:

making foo grow :
capacity changed : 1
capacity changed : 2
capacity changed : 3
capacity changed : 4
capacity changed : 6
capacity changed : 9
capacity changed : 13
capacity changed : 19
capacity changed : 28
capacity changed : 42
capacity changed : 63
capacity changed : 94
capacity changed : 141

g++ 运行结果如下:

making foo grow :
capacity changed : 1
capacity changed : 2
capacity changed : 4
capacity changed : 8
capacity changed : 16
capacity changed : 32
capacity changed : 64
capacity changed : 128

Ⅳ . vector 增删查改

01 pop_back() 尾删

代码实现:

void vector_test7() 
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);for (auto e : v) cout << e << " "; cout << endl;v.pop_back();   // 尾删:3for (auto e : v) cout << e << " "; cout << endl;v.pop_back();   // 尾删:2for (auto e : v) cout << e << " "; cout << endl;
}

运行结果如下:

02 assign() 赋值

用 n 个 value 覆盖:

void vector_test8() 
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.assign(10, 5);   // 原来是1到4,现在改成10个5
}

调试结果如下:

03 为什么 vector 不提供 find 接口

string、map、set 都有 find() 用,凭什么 vector 和 list 没有

其实,我们应该考虑的是 —— 为什么 string、map、set 能有 find 操作。

而 vector 之所以不提供 find ,是因为如果去查找元素效率就会是 O(n) ...

凭什么不让我 vector 用 find() ,我偏要用!

可以的,"algorithm库" 里有通用的 find 操作,我们来一睹其芳容 ——

#include <algorithm>

该 find 内部是从 begin 到 end 进行一次遍历,其复杂度是 O(n) 

值得一提的是,在C++中,凡是使用迭代器区间,都是左闭右开的

再去思考 map、set 为什么有 find() 通过迭代器从头到尾遍历 map 与 set 时,

得到的结果是按 key 排序的结果,而不是插入时的顺序,所以这两个容器没有 push_back 操作。

其实,插入到 map 与 set 中的元素会被组织到一颗红黑树上,红黑树是一颗平衡二叉树,

平衡二叉树是一颗二叉排序树,对一颗二叉排序树的查找有点像二分查找,复杂度是 ,

由于 map 与 set 的数据结构能有更快的查找方法,所以在容器内提供了 find 方法

04 通用查找 find()

如果非要在 vector 里用 find() ,我们可以用通用 find。

找到了:返回一个迭代器区间那个值的位置;

没找到:返回的是 last ,即右边开区间的位置。

代码演示:

void vector_test9() 
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator ret = find(v.begin(), v.end(), 3);// auto ret = find(v.begin(), v.end(), 3);if (ret != v.end()) {cout << "找到了" << endl;}
}

05 insert() 插入

比如我们刚才用通用 find 找到了 3 的位置,

我们想在这个位置前面插入一个数据,就可以使用 insert() 插入。

在 3 前面插入一个 30:

void vector_test9() 
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator ret = find(v.begin(), v.end(), 3);// auto ret = find(v.begin(), v.end(), 3);if (ret != v.end()) {cout << "找到了" << endl;v.insert(ret, 30);}for (auto e : v) cout << e << " "; cout << endl;
}

运行结果如下:

虽然没有 vector 没有提供 push_front,但是我们也可以用 insert 去头插

代码演示:

void vector_test10() 
{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;v.insert(v.begin(), -1);   // 在起始位置插入一个-1for (auto e : v) cout << e << " "; cout << endl;
}

运行结果如下:

06 erase() 删除

我们我们想删除数据,我们就可以用 erase 去删除

代码演示:

void vector_test11() 
{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;vector<int>::iterator pos = find(v.begin(), v.end(), 3);if (pos != v.end()) {   // 判断pos是否存在v.erase(pos);       // 删除pos}for (auto e : v) cout << e << " "; cout << endl;
}

运行结果如下:

如果没有判断会怎么样?

void vector_test11() 
{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;vector<int>::iterator pos = find(v.begin(), v.end(), 3);v.erase(pos);       for (auto e : v) cout << e << " "; cout << endl;
}

运行结果如下:

如果要删除的目标存在,不会怎么样。

怕的就是要删的目标不存在!比如我要删个 5,但是 vector 里只有 1,2,3,4 。

vector<int>::iterator pos = find(v.begin(), v.end(), 5);
v.erase(pos);

如果有了判断,就不会翻车了,如果待删目标不存在,就不会去走 erase()  

因为 pos 如果找不到就会等于 end() 上的值,我们利用这一点进行 if 判断

	vector<int>::iterator pos = find(v.begin(), v.end(), 5);if (pos != v.end()) {   // 检查!v.erase(pos);}

07 clear() 清空数据

void vector_test12() 
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);printf("清空前:");for (auto e : v) cout << e << " "; cout << endl;v.clear();printf("清空后:");for (auto e : v) cout << e << " "; cout << endl;
}

运行结果如下:

clear只是把数据清了,但容量还在

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

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

相关文章

大模型笔记5 Extractive QA任务评估

目录 Extractive QA任务评估 Extractive QA评测指标 precision, recall, f1 ROUGE 划分训练与评估数据集 token位置评估 单个token位置评估 输入label的token位置 预测token位置 评估 Wandb 共享机器同时登录 样本类别平衡 标记token label时对窗口进行筛选 训练…

IT运维岗适用的6本证书

作为IT从业人员&#xff0c;不断提升自身的专业技能和知识是提升职场竞争力、助力升职加薪的重要途径。特别是在运维领域&#xff0c;虽然工作看似简单&#xff0c;但实际上需要掌握的技术知识却相当全面。为了全面提升自己的技术能力&#xff0c;并证明自己的专业能力&#xf…

2024 年 7 月区块链游戏研报:市场波动与数据分化的挑战与机遇

作者&#xff1a;Stella L (stellafootprint.network) 数据来源&#xff1a;Footprint Analytics 游戏研究页面 7 月份&#xff0c;加密货币市场波动显著&#xff0c;价格表现各异。比特币和 Solana 表现抢眼&#xff0c;与此同时&#xff0c;以太坊在美国市场推出现货以太坊…

Python酷库之旅-第三方库Pandas(073)

目录 一、用法精讲 296、pandas.Series.dt.as_unit方法 296-1、语法 296-2、参数 296-3、功能 296-4、返回值 296-5、说明 296-6、用法 296-6-1、数据准备 296-6-2、代码示例 296-6-3、结果输出 297、pandas.Series.dt.days属性 297-1、语法 297-2、参数 297-3、…

零售企业中 SRM 系统与开源 AI 智能名片商城系统的协同作用

摘要&#xff1a;本文深入探讨了 SRM 系统在零售企业与上游供应商关系管理中的关键作用&#xff0c;并引入开源 AI 智能名片商城系统&#xff0c;细致分析了两者如何协同助力零售企业优化供应链、提升竞争力。通过阐述 SRM 系统的功能模块及其对零售企业的多方面积极影响&#…

WEB渗透未授权访问篇-Redis

测试 redis-cli redis-cli -h 127.0.0.1 flunshall 192.168.0.110:6379>ping PONG 存在未授权访问 JS打内网 var cmd new XMLHttpRequest(); cmd.open("POST", "http://127.0.0.1:6379"); cmd.send(flushall\r\n); var c…

8月6日笔记

8月6日 红日靶场打靶继续 SHOW VARIABLES #用于显示服务器运行时的各种系统变量的当前设置。这些变量可以控制服务器的行为在 MySQL 中&#xff0c;general_log 和 general_log_file 是两个与“general”相关的系统变量&#xff0c;它们控制着服务器是否启用一般查询日志以及…

重庆市合川区第二届网络安全“钓鱼城“杯部分题解

MISC 下载文件后&#xff0c;进行分析 往下划看见smb 最开始以为是通过smb协议下载的文件 找半天没发现&#xff0c;往前翻了翻&#xff0c;看见了flag 存储为原始数据 通过上述分析发现开头是pk&#xff0c;保存为zip压缩包 发现需要密码 感觉是伪加密 使用工具一把梭 再…

鸿蒙AI功能开发【hiai引擎框架-人脸识别】 基础视觉服务-人脸检查

介绍 本示例展示了使用hiai引擎框架提供的人脸识别能力。 本示例模拟了在应用里&#xff0c;选择一张图片&#xff0c;识别其多个人脸信息并展示出来。包括人脸框、五官点位、置信度、人脸朝向&#xff08;欧拉角&#xff09; 需要使用hiai引擎框架通用文字识别接口hms.ai.f…

vue前端自适应布局,一步到位所有自适应

页面展示 实现内容 1&#xff0c;左右布局 左侧固定宽带&#xff0c;右侧自适应剩余的宽度。中间一条分割线&#xff0c;可以拖拉&#xff0c;自适应调整左右侧的宽度。左侧的高度超长自动出现横向滚动条&#xff0c;左侧宽度超长&#xff0c;自动出现竖向滚动条。 2&#x…

媒体资讯视频数据采集-lux的使用

lux(annie)是个github上的一个开源项目&#xff0c;可以使用他来下载网上各个平台的视频、音频、图片。 支持的站点也不少**&#xff08;ps: 对于一些反爬机制较好的网站可能不能下载&#xff0c;比如抖音、快手&#xff09;** ​ github使用说明页面提供windows、linux、M…

SpringMVC (发送请求——>参数传递—— >响应数据)

设置请求访问路径 RequestMapper&#xff1a;将请求访问路径和我们业务层的方法联系起来 ResponseBody&#xff1a;将我们业务层方法的返回值转化为json&#xff0c;xml或其他格式的数据返回给页面 两种请求 get请求 post请求 测试案例 RequestMapping("/getNameAndAge&…

可观测性(observability)

一、定义 wiki百科的定义 In software engineering, more specifically in distributed computing, observability is the ability to collect data about programs’ execution, modules’ internal states, and the communication among components.[1][2] To improve obser…

Linux 快速构建LAMP环境

目录 部署方式&#xff1a; 基础环境准备&#xff1a; 1.安装Apache服务 &#xff08;1&#xff09;安装Apache &#xff08;2&#xff09;安装一些Apache的扩展包 2.安装PHP语言 &#xff08;1&#xff09;下载php软件仓库 &#xff08;2&#xff09;指定php安装版本…

HAProxy七层负载均衡配置方案

HAProxy 一、准备二、配置HAProxy服务器1. 下载HAProxy2. 编写配置文件3. 启动HAProxy服务 三、配置后端服务①配置web服务器②配置php服务器 四、测试 一、准备 准备5台CentOS7服务器&#xff0c;IP地址如下&#xff1a; HAProxy 192.168.152.71web1 192.168.152.72web2 192.…

第九届世界3D渲染大赛火热报名中

世界渲染大赛是一个汇聚世界顶尖CG艺术家的大赛&#xff0c;目前已经成功举办了八届&#xff0c;神仙打架般的作品让众多3D艺术家们直呼过瘾&#xff0c;如今第九届也在火热进行中&#xff0c;快来与众多世界顶尖艺术家们一决高下吧&#xff01;下面给大家介绍一下第九届的赛事…

成都数字产业中心崛起,树莓集团如何加速国际数字影像产业园的全球步伐?

在数字化浪潮的推动下&#xff0c;成都数字产业中心近年来强势崛起&#xff0c;展现出令人瞩目的发展态势。据统计&#xff0c;过去五年间&#xff0c;成都数字产业的年均增长率超过了 20%&#xff0c;这一数据充分证明了其强大的发展动力。而在这片充满活力与创新的土地上&…

《Unified Visual Relationship Detection with Vision and Language Models》ICCV2023

摘要 这项工作集中在训练单一的视觉关系检测器&#xff08;VRD&#xff09;&#xff0c;该检测器可以预测来自多个数据集的标签空间的并集。由于不同数据集的标签体系不一致&#xff0c;合并标签是一个挑战。作者提出了 UniVRD&#xff0c;一种新颖的自下而上的方法&#xff0…

MyIP:强大且简单好用!

在这个数字化的时代&#xff0c;IP地址就像是我们的网络身份证。各位在日常的工作中&#xff0c;肯定会会遇到需要和 IP 地址相关的需求。 今天和大家聊一聊一个非常好用的开源 IP 工具项目 - MyIP。 简介 MyIP一个开源IP工具箱&#xff0c;提供了一系列的网络检测工具&…

axios请求响应拦截器

目录 axios-拦截器 拦截器的作用 请求拦截器-基本写法: axios请求拦截器-统一设置token 需求: 核心步骤: 关键代码: 响应拦截器-基本写法: axios响应拦截器-统一处理token失效 需求: 核心步骤: 关键代码: axios响应拦截器-数据剥离 需求: 核心步骤: 关键代码: ax…