当前位置: 首页 > news >正文

C++——vector的了解与使用

目录

引言

vector容器的基本概念

1.功能

2.动态大小

3.动态扩展

vector的接口

1.vector的迭代器

2.vector的初始化与销毁

3.vector的容量操作

3.1 有效长度和容量大小

(1)使用示例

(2)扩容机制

3.2 有效长度和容量操作

(1)reserve

(2)resize

4.vector的访问操作

5.vector的修改操作

迭代器失效

结束语


引言

在我的博客 C++——string的了解和使用 中,我们学习了标准模板库(STL)中的string的一些基础内容,今天我们来学习 vector

vector容器的基本概念

在C++中,vector 是一个非常重要的容器,它属于标准模板库的一部分。vector 提供了一种动态数组的实现,可以在运行时动态地增加或减少其大小,同时保持元素的连续存储。

1.功能

vector是可变大小的序列容器,采用连续存储空间存储元素,可通过下标高效访问。

2.动态大小

与静态数组不同,vector 的大小可以在运行时动态地改变。此外,静态数组内数据通常存储在栈上,而vector中数据存储在堆上。

3.动态扩展

动态扩展的核心在于,当现有内存空间不足以满足需求时,不是简单地在原空间后续接新空间(这在连续内存分配中通常是不现实的,因为后续空间可能已被其他程序或数据占用),而是采取以下步骤:

(1)分配新空间:找到一个足够大的、连续的新内存空间。这个新空间的大小要能够容纳原数据和新数据。

(2)数据拷贝:将原内存空间中的数据复制到新分配的内存空间中。这个过程中需要确保数据的完整性和正确性。

(3)释放原空间:在数据成功拷贝到新空间后,释放原来的内存空间。这一步是为了避免内存泄漏。

(4)更新指针:将指向原内存空间的指针更新为指向新内存空间的指针。这样,程序就可以继续在新空间中操作数据。

此外,使用vector时必须包含头文件 #include<vector> 。

vector的接口

我们使用如下文档来辅助我们学习vector:

vector的接口详细介绍

1.vector的迭代器

与string一样,vector中也有迭代器。由于vector定义在vector类中,因此我们想要使用vector的迭代器需要通过域作用限定符访问——vector<类型>::iterator 。

其中,begin(),end(),rbeign(),rend()的使用访问方法与string中的类似,

我们来看看代码演示:

int main()
{vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };vector<int>::iterator it = vec.begin();cout << "顺序遍历:";while (it != vec.end()){cout << *it << " ";it++;}cout << endl;cout << "逆序遍历:";vector<int>::reverse_iterator rit = vec.rbegin();while (rit != vec.rend()){cout << *rit << " ";++rit;}return 0;
}

输出结果如下:

同样的,vector也支持const_iterator:

int main()
{vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };for (vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it) {std::cout << *it << " ";}std::cout << std::endl;return 0;
}

2.vector的初始化与销毁

vector 类的赋值运算符 operator= 被重载以支持将一个 vector 的内容复制到另一个 vector 中。

vector 支持多种构造函数,拷贝构造以及赋值运算符重载。

下面是一些简单的使用:

void printVector(vector<int>& vec)
{	for (vector<int>::iterator it = vec.begin(); it != vec.end(); ++it){cout << *it << " ";}cout << endl;
}int main()
{vector<int> vec1;							for (int i = 0; i < 5; ++i){vec1.push_back(i);}vector<int> vec2(vec1.begin(), vec1.end());	vector<int> vec3(5, 5);						vector<int> vec4(vec3);						cout << "打印vec2: ";printVector(vec2);cout << "打印vec3: ";printVector(vec3);cout << "打印vec4: ";printVector(vec4);return 0;
}

输出结果为:

int main()
{vector<int> vec1, vec2;for (int i = 0; i < 5; i++){vec1.push_back(i);}vec2 = vec1;printVector(vec2);return 0;
}

输出结果为:

3.vector的容量操作

如下表格是关于vector的一些基础的容量操作:

函数名称功能
size返回vector的有效长度
capacity返回vector的容量大小
clear清空vector
empty检查vector是否为空,是则返回ture,否则返回false
reserve请求改变vector的容量
resize重新设置有效元素的数量,超过原来有效长度则用c字符填充
3.1 有效长度和容量大小
(1)使用示例

与 string类 类似,我们可以使用 size()返回容器的有效长度;capacity()返回容器的容量大小。

下面是简单的测试用例:

int main()
{vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };cout << vec.size() << endl;cout << vec.capacity() << endl;if (vec.empty()){cout << "vec为空" << endl;}else{cout << "vec不为空" << endl;}vec.clear();if (vec.empty()){cout << "vec为空" << endl;}else{cout << "vec不为空" << endl;}return 0;
}

输出结果为:

通常来说,vector的有效长度和容量大小相同

(2)扩容机制

接下来我们来看看vector的扩容机制:

int main()
{size_t sz;vector<int> vec;sz = vec.capacity();cout << "making vec grow:" << endl;for (int i = 0; i < 100; ++i){vec.push_back(i);if (sz != vec.capacity()){sz = vec.capacity();cout << "capacity changed: " << sz << endl;}}
}

输出结果为:

在vs2022中,vector是以1.5倍进行扩容处理的,

我们现在把这段代码放到g++中运行看看:

我们可以看到,在此环境中,vector是以二倍进行扩容的。

3.2 有效长度和容量操作

接下来我们来学习vector中的reserve和resize(这俩函数的使用与string中的差不多)。

(1)reserve

reserve 函数用于请求改变容器的容量,即分配足够的内存空间以容纳至少指定数量的元素

简单使用一下:

int main()
{vector<int> vec;vec.reserve(10);cout << vec.capacity() << endl;return 0;
}

输出结果为:

(2)resize

resize的使用有如下两种:

resize(int num);

如果 num 小于当前容器的大小,那么容器末尾的多余元素将被删除。如果 num 大于当前容器的大小,则容器将被扩展,新添加的元素将被初始化为该类型的默认值(对于内置类型如 int,默认值为 0)。

resize(int num, int elem);

这个方法同样用于将 std::vector 的大小调整为 num,但在容器需要扩展时,新添加的元素将被初始化为 elem 而不是默认值。如果 num 小于当前容器的大小,多余元素的处理方式与第一个 resize 方法相同,即被删除。

简单的使用一下:

int main()
{vector<int> vec = { 1,2,3,4,5 };vec.resize(3);for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;vec.resize(4);for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;vec.resize(5, 9);for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;return 0;
}

输出结果为:

4.vector的访问操作

vector的访问操作有如下几个:

函数名称功能
operator[]返回指定位置的元素,越界则报错
at返回指定位置的元素,越界则抛异常
front返回字符串第一个元素
back返回字符串最后一个元素

这些函数的用法也与string中的函数用法差不多,就不多介绍了,来看看代码:

int main()
{vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;for (int i = 0; i < vec.size(); i++){cout << vec.at(i) << " ";}cout << endl;cout << "front:" << vec.front() << endl;cout << "back:" << vec.back() << endl;return 0;
}

输出结果为:

5.vector的修改操作

vector的修改操作有如下几个:

函数名称功能
push_back在数组后追加元素
pop_back删除数组最后一个元素
insert在指定位置追加元素
assign使用指定数组替换原数组
erase删除数组指定部分区间
swap交换两个数组

先来看看push_back(),pop_back(),assign(),swap() :

int main()
{vector<int> vec1 = { 0,1,2,3,4,5,6,7,8,9 };cout << "back:" << vec1.back() << endl;// 元素尾插vec1.push_back(10);// 元素尾删cout << "back:" << vec1.back() << endl;vec1.pop_back();cout << "back:" << vec1.back() << endl;vector<int> vec2 = { 9,9,9,9,9 };vec2.assign(3, 3);for (int i = 0; i < vec2.size(); i++){cout << vec2[i] << " ";}cout << endl;vec2.swap(vec1);for (int i = 0; i < vec1.size(); i++){cout << vec1[i] << " ";}cout << endl;for (int i = 0; i < vec2.size(); i++){cout << vec2[i] << " ";}cout << endl;return 0;
}

输出结果如下:

我们再来看看insert和erase:

insert函数:

来看代码:

int main()
{vector<int> vec1(5, 10);vector<int>::iterator it = vec1.begin();it = vec1.insert(it, 100);cout << "vec1:";for (it = vec1.begin(); it < vec1.end(); it++){cout << *it << " ";}cout << endl;vec1.insert(it, 2, 1000);it = vec1.begin();cout << "vec1:";for (it = vec1.begin(); it < vec1.end(); it++){cout << *it << " ";}cout << endl;vector<int> vec2(2, 10000);it = vec1.begin();vec1.insert(it + 2, vec2.begin(), vec2.end());cout << "vec1:";for (it = vec1.begin(); it < vec1.end(); it++){cout << *it << " ";}cout << endl;return 0;
}

输出结果为:

erase函数:

简单的代码演示如下:

int main()
{vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };vector<int>::iterator it = vec.erase(vec.begin() + 3);	// 删除值为3的元素it = vec.erase(it);	// 删除值为4的元素for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;it = vec.erase(vec.begin(), vec.begin() + 5);for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;return 0;
}

输出结果为:

迭代器失效

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

以下可能会导致迭代器失效:

1.会引起其底层空间改变的操作,都有可能使迭代器失效

int main()
{vector<int> v{ 1,2,3,4,5,6 };auto it = v.begin();// 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容// v.resize(100, 8);// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变// v.reserve(100);// 插入元素期间,可能会引起扩容,而导致原空间被释放// v.insert(v.begin(), 0);// v.push_back(8);// 给vector重新赋值,可能会引起底层容量改变//v.assign(100, 8);/*出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉,而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的空间,而引起代码运行时崩溃。解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新赋值即可。	   */while (it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}

2.指定位置元素的删除操作--erase

int main()
{int a[] = { 1, 2, 3, 4 };vector<int> v(a, a + sizeof(a) / sizeof(int));// 使用find查找3所在位置的iteratorvector<int>::iterator pos = find(v.begin(), v.end(), 3);// 删除pos位置的数据,导致pos迭代器失效。v.erase(pos);cout << *pos << endl; // 此处会导致非法访问return 0;
}

3.与vector一样,string在插入+扩容操作+erase之后,迭代器也会失效

int main()
{string s("hello");auto it = s.begin();// 放开之后代码会崩溃,因为resize到20会string会进行扩容// 扩容之后,it指向之前旧空间已经被释放了,该迭代器就失效了// 后序打印时,再访问it指向的空间程序就会崩溃//s.resize(20, '!');while (it != s.end()){cout << *it;++it;}cout << endl;it = s.begin();while (it != s.end()){it = s.erase(it);// 按照下面方式写,运行时程序会崩溃,因为erase(it)之后// it位置的迭代器就失效了// s.erase(it);  ++it;}return 0;
}

结束语

写完啦~\(≧▽≦)/~

接下来会愈加忙碌,希望自己还能挤出时间写博客=_=

感谢各位大佬的支持!!!

求点赞收藏评论关注!!!

相关文章:

C++——vector的了解与使用

目录 引言 vector容器的基本概念 1.功能 2.动态大小 3.动态扩展 vector的接口 1.vector的迭代器 2.vector的初始化与销毁 3.vector的容量操作 3.1 有效长度和容量大小 (1)使用示例 (2)扩容机制 3.2 有效长度和容量操作 (1)reserve (2)resize 4.vector的访问操作…...

Ubuntu设置静态IP地址

Ubuntu如果是最小安装&#xff0c;没有图形界面&#xff0c;需要配置静态IP&#xff0c;该怎么操作呢&#xff1f; Netplan 是最新版 Ubuntu 的默认网络管理工具。Netplan 的配置文件使用 YAML 编写&#xff0c;扩展名为 .yaml。 注意&#xff1a;配置文件中的空格是语法的一部…...

力扣349.两个数组的交集

题目链接&#xff1a;349. 两个数组的交集 - 力扣&#xff08;LeetCode&#xff09; 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的 交集。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,2,…...

FreeRTOS - 软件定时器

在学习FreeRTOS过程中&#xff0c;结合韦东山-FreeRTOS手册和视频、野火-FreeRTOS内核实现与应用开发、及网上查找的其他资源&#xff0c;整理了该篇文章。如有内容理解不正确之处&#xff0c;欢迎大家指出&#xff0c;共同进步。 1. 软件定时器 软件定时器也可以完成两类事情…...

Python的Atlassian第三方库的详细介绍

atlassian-python-api 是一个用于与 Atlassian 生态系统进行交互的 Python 库&#xff0c;支持与多种 Atlassian 工具&#xff08;如 Jira、Confluence、Bitbucket 等&#xff09;进行 API 调用。它简化了 REST API 的调用&#xff0c;提供了高层次的抽象&#xff0c;方便开发者…...

Java中的基本循环结构详解

在Java编程中&#xff0c;循环是控制流的重要组成部分&#xff0c;用于重复执行一段代码。Java提供了三种基本的循环结构&#xff1a;for循环、while循环和do-while循环。本文将详细介绍这三种循环的语法和使用场景&#xff0c;并通过示例代码展示其应用。 一&#xff0c;for …...

关于Git Bash中如何定义alias

一、在一次临时Bash会话中使用alias 在Bash中直接输入alias xxdddd&#xff0c;xx为对应要执行的命令的缩写&#xff0c;dddd为要执行的命令&#xff0c;如alias ddcd /d&#xff0c;输入完成后&#xff0c;在Bash中输入dd&#xff0c;即可切换至D盘。 此种设置方式&#xff…...

luckfox1106初次使用

luckfox1106初次使用 下载rk驱动 https://files.luckfox.com/wiki/Luckfox-Pico/Software/DriverAssitant_v5.12.zip 安装驱动 SD 卡烧录工具 https://files.luckfox.com/wiki/Luckfox-Pico/Software/SocToolKit_v1.98_20240705_01_win.zip 右键以管理员方式运行...

ab命令深入解析:ApacheBench性能测试工具

软考鸭微信小程序 学软考,来软考鸭! 提供软考免费软考讲解视频、题库、软考试题、软考模考、软考查分、软考咨询等服务 引言 在Web开发和运维领域&#xff0c;性能测试是评估服务器和应用性能的重要手段。ApacheBench&#xff08;简称ab&#xff09;是Apache HTTP服务器自带的…...

VSCode创建VUE项目(二)前端登录页面

一.创建登录页面 代码&#xff1a; <template><div class"login-container dis-h"><div class"login-form dis-h"><div class"dis-v left"><span> 欢迎~ </span><span> VUE 新世界 </span>&l…...

centos 8.4学习小结

1.权限委派 2.vim快捷方式 2.1非正常关闭文本处理方式 2.2快捷方式 2.3TAB键补齐安装包 [ rootcloud Packages]# rpm -ivh bash-completion-2.7-5.el8.noarch.rpm 2.4#history 查询历史记录 [rootcloud ~]# vim /etc/profile HISTSIZE1000&#xff08;默认保存1000条历史记…...

AI 设计工具合集

&#x1f423;个人主页 可惜已不在 &#x1f424;这篇在这个专栏AI_可惜已不在的博客-CSDN博客 &#x1f425;有用的话就留下一个三连吧&#x1f63c; ​ 前言: AI 视频&#xff0c;科技与艺术的精彩融合。它借助先进的人工智能技术&#xff0c;为影像创作带来全新可能。本书…...

mac 源代码安装openresty

1. clone源代码 git clone https://github.com/openresty/openresty.git 2. 安装依赖包 brew install hg unix2dos brew install pcre openssl 3. 编译 make 4. 安装openresty cd openresty-1.27.1.1 ./configure --prefix/opt/openresty --with-http_ssl_module --with-…...

人工智能和机器学习之线性代数(二)

人工智能和机器学习之线性代数(二) 本文Linear Algebra 101 for AI/ML – Part 2将通过介绍向量的点积(dot Product)、Embedding及其在相似性搜索中的应用来建立这些基础知识。 将学习Embedding&#xff0c;Embedding是表示概念、对象和想法的特殊类型的向量。Embedding在整个…...

Postman中的form-data 和 JSON 的区别

在使用 Postman 进行 API 测试时&#xff0c;form-data 和 JSON 是两种常用的请求体格式&#xff0c;它们有以下几个主要区别&#xff1a; 1. 数据格式 form-data: 主要用于表单数据的提交&#xff0c;适合文件上传和键值对的数据传递。数据以键值对的形式编码&#xff0c;类似…...

网络安全基础知识点_网络安全知识基础知识篇

文章目录 一、网络安全概述1.1 定义1.2 信息安全特性1.3 网络安全的威胁1.4 网络安全的特征 二、入侵方式2.1 黑客2.1.1 入侵方法2.1.2 系统的威胁2.2 IP欺骗与防范2.2.1 TCP等IP欺骗基础知识2.2.2 IP欺骗可行的原因2.2.3 IP欺骗过程2.2.4 IP欺骗原理2.2.5 IP欺骗防范2.3 Sniff…...

Vue.js 从入门到精通:全面解析组件化、路由与状态管理(附 Todo 案例)

在当今的前端开发领域&#xff0c;Vue.js 以其简洁、高效和灵活的特点受到了广泛的关注和应用。本文将带你从 Vue 的基础知识入手&#xff0c;逐步深入到高级特性&#xff0c;让你对 Vue 有一个全面的了解&#xff0c;并通过实际案例帮助你更好地掌握 Vue 的开发。 一、Vue 简…...

AI Weekly#1:过去一周重要的AI资讯汇总

&#x1f680;热点头条 诺贝尔奖青睐AI领域&#xff1a;2024年诺贝尔物理学奖和化学奖均授予了与人工智能相关的研究。物理学奖颁发给了约翰霍普菲尔德和杰弗里辛顿&#xff0c;表彰他们在机器学习领域的开创性工作。化学奖则授予了大卫贝克、德米斯哈萨比斯和约翰江珀&#xf…...

图论刷题

卡码网 98. 所有可达路径 使用邻接矩阵存储&#xff1a; #include<iostream> #include<vector> using namespace std;vector<vector<int>>res;//收集符合条件的路径vector<int>path;//0节点到终点的路径//确定递归函数 参数和返回值void dfs(c…...

ICM20948 DMP代码详解(85)

接前一篇文章:ICM20948 DMP代码详解(84) 上一回解析了inv_icm20948_ctrl_enable_sensor函数的大部分代码,只剩下一行代码没有解析。为了便于理解和回顾,再次贴出inv_icm20948_ctrl_enable_sensor函数源码,在EMD-Core\sources\Invn\Devices\Drivers\ICM20948\Icm20948Data…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例

文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?

论文网址&#xff1a;pdf 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔记&#xff0c;谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...