C++必修:STL之vector的了解与使用

✨✨ 欢迎大家来到贝蒂大讲堂✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:C++学习
贝蒂的主页:Betty’s blog

1. C/C++中的数组

1.1. C语言中的数组

在 C 语言中,数组是一组相同类型元素的有序集合。与字符串类似,它的大小在编译时就已经确定,不可更改。

//大小为5的整型数组
int arr1[5] = { 1,2,3,4,5 };
//大小为5的浮点型数组
double arr2[5] = {0.0};

1.2. C++中的数组

同样与string类似,C++为了更加方便就引入了一个支持可动态大小数组的序列容器vecotr。其特点如下:

  1. vector是可变大小的序列容器,采用连续存储空间存储元素,可通过下标高效访问。
  2. 与数组不同,vector大小可动态改变,由容器自动处理。
  3. vector本质上用动态分配数组存储元素,插入新元素时可能重新分配空间,即分配新数组并移动全部元素,此操作时间代价高,但不是每次插入都重新分配。
  4. vector会分配额外空间适应增长,不同库策略不同,但重新分配通常是对数增长间隔,使末尾插入元素能在常数时间完成。
  5. dequelistforward_list相比,vector访问元素及末尾添加和删除元素更高效,非末尾的删除和插入操作效率低,且统一的迭代器和引用更好。
//整型数组
vector<int> v1;
//浮点型数组
vector<double> v2;

并且注意每次使用vector都需要包含头文件#include<vector>。并且vector是一个模版类,所以在使用时需要显示实例化

2. vector的接口

接下来我们将介绍一些vector的常见接口,因为很多接口的作用都与string的接口非常类似,所以很多就不在详细说明,大家具体也可以参考vector的使用。

img

2.1. vector的迭代器

同样的vector中也存在迭代器iterator,因为定义在vector类中,所以其需要通过域作用限定符访问——vector<类型>::iterator

下面将介绍的begin()end()rbeign()rend()的使用访问方法与string中的几乎一摸一样,我们直接上实例演示:

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

img

当然vector也支持const_iterator,用法也类似,这里就不在赘述。

2.2. vector的初始化与销毁

img

img

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

void Test2()
{//1.默认构造函数初始化vector<int> v1;//2.n个val初始化vector<int> v2(3, 2);string s("abcd");//3.利用迭代器区间初始化vector<int> v3(s.begin(), s.end());//4.拷贝构造vector<int> v4(v3);//5.赋值重载v2 = v3;//6.可变参数列表初始化vector<int> v5 = { 1,2,3,4,5 };vector<char> v6 = v4;//error 不同类型不能赋值
}

其中需要注意的是可变参数列表初始化,这是在C++11之后支持的新语法,具体讲解我们之后再谈。

2.3. vector的容量操作

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

vector类中,我们同样可以通过size()容器的有效长度;capacity()返回容器的容量大小。

img

void Test3()
{vector<int> v = { 1,2,3,4,5 };cout << v.size() << endl;cout << v.capacity() << endl;
}

img

在初始化时,vecotr中的sizecapacity一般相同。这时我们也可以通过以下程序探究一下其扩容机制:

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

img

在VS环境下,vector一般是以1.5倍扩容。但是在Linux环境下一般就以2倍扩容。

img

至于clear()empty()两个函数用法就十分简单,这里就不在赘述了。

2.3.2. 有效长度与容量操作

接下来我们来使用一下vector中的resize()reserve()。其实他们的用法与特点也是与string类中的相同,我们直接上手即可

  1. n<sz时,reserve并不会发生任何改变,resize会删除有效字符到指定大小。
  2. sz<n<capcity时,reserve并不会发生任何改变,resize会补充有效字符(默认为0)到指定大小。
  3. n>capacity时,reserve会发生扩容,resize会补充有效字符(默认为0)到指定大小。
void Test4()
{vector<int> v1 = { 1,2,3,4,5 };cout << "v1的有效长度为:" << v1.size() << endl;cout << "v1的容量大小为:" << v1.capacity() << endl;v1.reserve(10);cout << "v1的有效长度为:" << v1.size() << endl;cout << "v1的容量大小为:" << v1.capacity() << endl;v1.resize(8, 10);for (auto& e : v1){cout << e << " ";}
}

img

在这里我们需要注意一个经典错误,如下列代码:

void Test5()
{vector<int> v;v.reserve(10);for (int i = 0; i < 10; i++){v[i] = i;}for (auto& e : v){cout << e << " ";}
}

img

一旦运行就会发生如上错误,这是为什么呢?因为reserve只是改变了容量capacity并没有改变size,而operator[]访问时元素时是禁止访问下标size以后的元素的,一旦访问就会直接报错。

2.4. vector的访问操作

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

这四个函数的用法也与string中的函数用法相同,我们就直接上手示例

void Test6()
{vector<int> v = { 1,2,3,4,5 };for (int i=0;i<v.size();i++){cout << v[i] << " ";}cout << endl;for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;cout << "front:" << v.front() << endl;cout << "back:" << v.back() << endl;
}

img

2.4. vector的修改操作

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

我们首先先介绍最简单的四个函数push_back()pop_back()assign()swap()

void Test7()
{vector<int> v = { 1,2,3,4,5,6 };cout << "back:" << v.back() << endl;//尾插v.push_back(7);//尾删cout << "back:" << v.back() << endl;v.pop_back();cout << "back:" << v.back() << endl;vector<int> vv = { 6,5,4,3,2,1 };//n个val赋值给原数组vv.assign(3, 2);for (int i = 0; i < vv.size(); i++){cout << vv[i] << " ";}cout << endl;vv.swap(v);for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;for (int i = 0; i < vv.size(); i++){cout << vv[i] << " ";}
}

img

然后我们来介绍insert()与·earse()的用法,这两个函数的用法就与string中的有所不同。首先是insert()函数:

img

void Test8()
{vector<int> myvector(3, 100);vector<int>::iterator it = myvector.begin();//1.向指定位置插入一个元素it = myvector.insert(it, 200);cout << "myvector contains:";for (it = myvector.begin(); it < myvector.end(); it++)cout << ' ' << *it;cout << endl;//2.向指定位置插入n个元素myvector.insert(it, 2, 300);cout << "myvector contains:";for (it = myvector.begin(); it < myvector.end(); it++)cout << ' ' << *it;cout << endl;//3.向指定位置插入一段迭代器区间it = myvector.begin();vector<int> anothervector(2, 400);cout << "myvector contains:";for (it = myvector.begin(); it < myvector.end(); it++)cout << ' ' << *it;cout << endl;it = myvector.begin();myvector.insert(it + 2, anothervector.begin(), anothervector.end());//4.向指定位置插入一段迭代器区间int myarray[] = { 501,502,503 };myvector.insert(myvector.begin(), myarray, myarray + 3);cout << "myvector contains:";for (it = myvector.begin(); it < myvector.end(); it++)cout << ' ' << *it;cout << endl;
}

img

接下来我们继续来使用erase()函数

img

void Test9()
{//1.删除迭代器所指元素vector<int> myvector;for (int i = 1; i <= 10; i++) myvector.push_back(i);vector<int>::iterator it = myvector.erase(myvector.begin() + 5);it = myvector.erase(it);//2.删除一段迭代器区间it = myvector.erase(myvector.begin(), myvector.begin() + 3);cout << "myvector contains:";for (int i = 0; i < myvector.size(); ++i)cout << ' ' << myvector[i];cout << endl;
}

img

虽然看起来vectorinsert()erase()string的没有什么区别,但是仔细观察就可以发现我们每次使用完迭代器之后都会更新,这是为什么呢?

主要还是因为我们每次插入数组都可能发生扩容,而扩容分为就地扩容与异地扩容。如果发生的异地扩容,这时的迭代器就不在指向原来的空间,而就指向一块释放的内存,我们一旦继续访问就会报错,这种现象我们称为迭代器失效。为了避免出现这种情况,所以我们在使用完迭代器之后需要更新。

img

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

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

相关文章

泰迪智能科技AI大模型某医院合作案例介绍

泰迪智能科技AI大模型支持以ChatGLM2-6B、Baichuan-13B、Qwen14B和文心一言等多种大语言模型为底座&#xff0c;实现基于特定领域数据、面向智能客服、问答系统、自动摘要、智能打标、内容创作、信息抽取等应用场景的模型微调、评估和推理&#xff0c;为业务智能升级和价值挖掘…

【C++从小白到大牛】类和对象

目录 一、面向过程和面向对象初步认识 二、类的引入 三、类的定义 类的成员函数两种定义方式&#xff1a; 1. 声明和定义全部放在类体中 2. 类声明放在.h文件中&#xff0c;成员函数定义放在.cpp文件中 成员变量命名规则的建议&#xff1a; 四、类的访问限定符 【访问限…

本地部署持续集成工具Jenkins并配置公网地址实现远程自动化构建

文章目录 前言1. 安装Jenkins2. 局域网访问Jenkins3. 安装 cpolar内网穿透软件4. 配置Jenkins公网访问地址5. 公网远程访问Jenkins6. 固定公网地址 前言 本文主要介绍如何在Linux CentOS 7中安装Jenkins并结合cpolar内网穿透工具实现远程访问管理本地部署的Jenkins服务. Jenk…

大模型算法面试题(十八)

本系列收纳各种大模型面试题及答案。 1、P-tuning v2 思路、优缺点是什么 P-tuning v2是清华大学自然语言处理实验室&#xff08;THUDM&#xff09;等研究机构提出的一种新的预训练模型优化方法&#xff0c;主要关注如何通过动态构建任务相关的提示序列来引导预训练模型进行更…

【数据结构进阶】手撕红黑树

&#x1f525;个人主页&#xff1a; Forcible Bug Maker &#x1f525;专栏&#xff1a; C || 数据结构 目录 &#x1f308;前言&#x1f525;红黑树的概念&#x1f525;手撕红黑树红黑树结点的定义红黑树主体需要实现的成员函数红黑树的插入findEmpty和Size拷贝构造析构函数和…

Redis和Mysql如何保持数据一致性

一般情况下&#xff0c;Redis是用来实现应用和数据库之间读操作得缓存层&#xff0c;主要目的是减少数据库IO&#xff0c;还可以提升数据的IO性能。 当应用程序需要去读取某个数据时&#xff0c;会首先尝试去Redis里面加载&#xff0c;如果命中就直接返回&#xff0c;如果没有…

C++ 操作Git仓库

代码 #include "common.h" #include "args.c" #include "common.c"enum index_mode {INDEX_NONE,INDEX_ADD };struct index_options {int dry_run;int verbose;git_repository* repo;enum index_mode mode;int add_update; };/* Forward declar…

vue项目Nginx部署启动

1.vue打包 &#xff08;1&#xff09;package.json增加打包命令 "scripts": {"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --host 10.16.14.110","start": "npm run dev","un…

Halcon 边缘提取(亚像素)

Halcon提供多种边缘提取算法。像素提取方法有常用的边缘提取算子或深度学习分割模型等。考虑到精度问题可能需要提取亚像素边缘。当然也可以提取轮廓&#xff1a;线、圆、椭圆等。本文只讨论提取轮廓。 1 基本概念 正常情况下&#xff0c;无需特殊操作即可提取边缘轮廓。 1…

Linux-4:Shell编程——基础语法(50%-100%)

目录 前言 一、数组 1.数组定义 2.关联数组 3.数组长度 二、运算符 1.算术运算符 2.关系运算符 3.布尔运算符 4.逻辑运算符 5.字符串运算符 6.文件测试运算符 三、read命令 1.接收用户输入 2.开启转义 3. -p 输入提示 4. -s 静默模式 -t 设置超时时间 5.读取…

Fiddler学习笔记

目录 前言 简介 原理 界面 前言 测试可以使用fiddler工具&#xff0c;通过抓包的方式修改前端参数和模拟后端返回&#xff0c;快速定位缺陷。 简介 Fiddler是HTTP协议调试代理工具&#xff0c;可以记录并检查所有客户端和服务器之间的HTTP和HTTPS请求&#xff0c;允许监视…

算法训练1

01背包问题 背包状态方程----动态规划 二维dp 使用 f[i][j] max(f[i-1][j] ,f[i-1][j - w[i]] v[i]); 伪代码&#xff1a; int dp[100][100]; void test6() {int n; //装备数量int m; //背包容量int v[105], w[105]; //前面空间&#xff0c;后面价值for (int i 1; i &l…

ONLYOFFICE文档:为企业和开发者带来强大的文档编辑功能

本文给大家介绍一个开源项目&#xff1a;ONLYOFFICE文档&#xff0c;它能够为文档编辑、多人协作提供强大支持。无论你是个人使用&#xff0c;还是企业、商业开发&#xff0c;都能找到适合你的版本。 关于 ONLYOFFICE 文档 ONLYOFFICE 文档是一套功能强大的文档编辑器&#x…

微信小程序获取AppSecret的步骤

文章目录 微信小程序获取AppSecret的步骤&#xff1a;注意&#xff1a; 微信公众平台 小程序的密钥&#xff08;或称为AppSecret&#xff09;是用于加密解密、验证服务器身份等安全操作的敏感信息。不同的平台&#xff08;如微信小程序、支付宝小程序、百度智能小程序等&am…

vulhub:Apache解析漏洞apache_parsing

在Apache1.x/2.x中Apache 解析文件的规则是从右到左开始判断解析&#xff0c;如果后缀名为不可识别文件解析&#xff0c;就再往左判断。如 1.php.xxxxx 漏洞原理 Apache HTTPD 支持一个文件拥有多个后缀&#xff0c;并为不同后缀执行不同的指令。比如如下配置文件 AddType te…

【C#】.net core 6.0 webapi 使用core版本的NPOI的Excel读取数据以及保存数据

欢迎来到《小5讲堂》 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 背景读取并保存NPOI信息NPOI 插件介绍基本功能示例代码写入 Excel 文件…

算法小白的进阶之路(力扣1~5)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…

花几千上万学习Java,真没必要!(三十九)

1、BufferedReader的使用&#xff1a; 测试代码&#xff1a; package test.com; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class FileReadToList { pu…

使用 openai 和 langchain 调用自定义工具完成提问需求

我们提供了一个函数&#xff0c;接受传入运算的字符串&#xff0c;返回运算的结果。 现在的需求是&#xff0c;我们问 gpt 模型&#xff0c;由于模型计算能力并不好&#xff0c;他要调用计算函数&#xff0c;根据计算结果&#xff0c;回答我们的问题。 使用 openai 实现&#…

发布NPM包详细流程

制作 首先需要制作一个npm包。 按照以下步骤依次执行。 mkdir my-npm-package cd my-npm-package npm init 相信这一步不需要过多的解释&#xff0c;就是创建了一个文件夹&#xff0c;然后初始化了一下文件夹。 然后在生成的package.json文件夹中更改一下自己的配置&…