【C++】vector容器的基本使用

news2024/9/20 10:44:42

一、vector是什么

vector是STL第一个正式的容器,它的底层其实就是动态数组,插入数据时当容量满了会自动扩容,它和string差不多,不同的之处之一在于vector本身是一个模板,它这个容器中可以存放各种各样的类型的数据,而string已经是模板实例化之后的结果。

vector类模板的第一个参数是T,其实就是你要放进容器中数据的类型,第二个参数我们暂且不管,它是一个空间配置器,主要是提高效率的,我们在实例化时暂且不传第二个参数,用它的默认缺省值,我们暂且只传第一个参数即可。

在本篇中涉及到allocator空间配置器的我们暂且不用管,可以先忽略。

 vector大多数接口和string的功能用法上没有什么太大的区别,这篇文章不会细讲,所以建议大家先去看一下这篇文章 -> string类的基本实现

二、基本使用

1、构造函数

C++98版本下有4个构造函数,我们这里只说C++98,不谈论其它版本。

我们来看一下它的使用:

void test_vector1()
{
	vector<int> v1;  //(1)默认构造

	vector<int> v2(10,1); //(2)带参构造,int类型的10个1

	vector<int> v3(v2.begin(),v2.end()); //(3)迭代器区间构造

	vector<int> v4(v3); //(4)拷贝构造
}

带有空间配置器的构造函数,我们用它的缺省值。

value_type就是模板的第一个参数T,即容器中存放数据的类型。

通过调试,我们可以看到各个容器中的内容:
 

2、析构函数

析构函数就不用多说了,我们创建容器添加数据,要在堆上开辟动态空间,析构函数就是要来对这些开辟的空间进行释放的,从而销毁容器对象。编译器会自动调用析构函数,我们可以不用单独处理。

我们可以通过调试简单演示一下:

程序结束前:

程序结束后:

程序结束自动调用析构,销毁容器对象。

3、赋值重载

它的作用就是将 x 中的所有元素复制到容器中。

我们用代码来理解一下:

void test_vector2()
{
	vector<int> v1(2,6);
	vector<int> v2(3,1);

	v2 = v1;
}

调试结果:

 赋值前:

赋值后:

 

从这两张图可以看出,当v2的size大小取决于v1,如果v2在赋值前容量比v1大,则赋值后保持不变,否则会扩容,保证能存放完v1的数据。

4、重载[]

因为vector的底层是动态数组,所以它也支持用[]来访问指定下标的元素。

void test_vector3()
{
	vector<int> v(6, 6);

	cout << v[0] << endl;
	cout << v[2] << endl;
}

在主函数中调用test_vector3()结果如下:

如果越界访问就会报错。

这里也有3种遍历容器的方法,和string差不多一样:

void test_vector4()
{
	vector<int> v1;
	vector<int> v2(10, 1);

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

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

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

	//3、范围for
	for (auto e : v3)
	{
		cout << e << " ";
	}
	cout << endl;
}

在主函数中调用test_vector4()结果如下: 

  

这3种迭代方法,我们在string篇幅都已详细讲解了,大家如果不懂,可以看一下那篇文章。

5、扩容规律

 我们可以看一下vector在添加元素时,自动扩容的规律:

void TestVectorExpand()
{
	size_t sz;
	vector<int> v;

	sz = v.capacity();
	cout << "capacity changed: " << sz << '\n';

	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';
		}
	}
}

 在主函数中调用TestVectorExpand()结果如下:

不难发现,它是从0开始扩的,这与string是不同的,它是严格的1.5倍扩容。

6、成员函数

成员函数中大多和string用法和功能一样,这里只说一些特殊的。

(1)reserve()

它的功能是也是预留容量的,也就是改变capacity的大小,它可以避免频繁扩容。

size_type是一个无符号整形,它和string中的reserve()成员函数相似,但有一点不同,我们先往下看,假设参数是n(就是改变后的容量大小),分3种情况:

1、n < size

明确不会缩容。(这是和string不同的)

也不会改变size的大小,就是不会破坏原有内容。

2、size < n < capacity

明确不会缩容。(这是和string不同的)

3、n > capacity

会扩容,至少扩到n,也可能更多,这是不确定的。

我们写一段代码验证一下:

void test_vector5()
{
	vector<int> v(10, 1);
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	//1、 n > capacity
	v.reserve(20); 
	cout << v.size() << endl;
	cout << v.capacity() << endl;


	//2、size < n < capacity
	v.reserve(15);
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	//3、n < size
	v.reserve(5);
	cout << v.size() << endl;
	cout << v.capacity() << endl;
}

在主函数中调用test_vector5()结果如下: 

根据结果显示,当n < capacity时,它是不会缩容的,这是明确的。 

(2)resize()

它是将size设置为n,也分3种情况:

1、n < size

size的大小会变为n,其余的size - n个元素被删除(摧毁),但capacity通常不变。

2、size < n < capacity

size的大小会变为n,插入n - capacity个数据,如果不给第二个参数,那就用给的缺省值来初始化这n - capacity个数据,如果value_type是自定义类型,就调用它的默认构造,如果想自己初始化这n - capacity个数据,那么就手动给第二个参数赋值。

3、n > capacity

会扩容,至少扩到n,也可能更多,这是不确定的。在vs下通常会扩的更多一些。

对于前两点,缩不缩容不一定,这个需要看平台的处理。

我们写一段代码验证一下:

void test_vector6()
{
	vector<int> v(3, 1);
	v.reserve(8); //提前预留8字节空间
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	//1、n < size
	v.resize(1);
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	//2、size < n < capacity
	v.resize(5, 3); //多余的n - size个数的数据初始化为3
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	//3、size > capacity
	v.resize(10,100);//多余的n - size个数的数据初始化为100
	cout << v.size() << endl;
	cout << v.capacity() << endl;
}

 在主函数中调用test_vector6()结果如下:

大家对比上面的3点进行理解。 

(3)insert()

这里的insert比string当中的insert简洁了许多。

它在这不支持下标了,只支持迭代器。 

void test_vector7()
{	
	vector<int> v2(2, 0);

	vector<int> v1(5, 1);
	for (auto e : v1)
		cout << e << " ";
	cout << endl;

	v1.insert(v1.begin(), 0); //(1)在v1头部位置插入0
	for (auto e : v1)
		cout << e << " ";
	cout << endl;

	v1.insert(v1.begin() + 3, 3, 100); //(2)在v1下标为3的位置上插入3个100
	for (auto e : v1)
		cout << e << " ";
	cout << endl;

	v1.insert(v1.end(), v2.begin(), v2.end());//(3)在v1的末尾,插入一段迭代区间
	for (auto e : v1)
		cout << e << " ";
	cout << endl;
}

 在主函数中调用test_vector7()结果如下: 

它不直接支持下标,但间接却是支持的,因为用迭代器就可以实现下标的问题,假设你要在下标为3的位置插入数据,那迭代器 v.begin() + 3就可以实现。这里没有用下标更多的原因是和后面的容器进行兼容,像list,它的底层不是动态数组,用下标访问就是不合适的。所以我们在容器这一部分,统一都用迭代器。

 (4)erase()

同时,它也是只支持用迭代器来进行相应位置数据删除。 

7、其他

vector不支持流插入和流提取,因为它的打印形式是多样的,不像string那样是固定的,遇到'\0'就终止打印,vector不支持流插入和流提取方便了我们对打印形式的控制,更自由和灵活。

vector底层是动态数组,string底层也是动态数组,那vector<char> 可以等同于string吗?

答案是不能。

首先,string定义的对象后面默认有'\0',vector<char>没有,其次,string定义的对象可以用字符串进行初始化,vector<char>不能,接着,string有很多针对字符串具有特定功能的接口,vector却没有,最后,string可以进行一些接口的传参,如果换用vector<char>则会麻烦许多。

所以vector<char> 是不可以取代string的。

三、结语

以上就是本篇的全部内容了,主要讲了vector的基本使用,希望大家有所收获,祝大家天天开心!

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

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

相关文章

【每日刷题】Day123

【每日刷题】Day123 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 673. 最长递增子序列的个数 - 力扣&#xff08;LeetCode&#xff09; 2. LCR 083. 全排列 - 力扣&…

C语言 | Leetcode C语言题解之题409题最长回文串

题目&#xff1a; 题解&#xff1a; int longestPalindrome(char * s) {int c[128]{0},ret0;for(int i0;i<strlen(s);i){c[s[i]];}for(int i0;i<128;i){retc[i]-c[i]%2;}return ret(ret!strlen(s)); }

【Qt】控件样式案例

例子&#xff1a;设置按钮样式 &#xff08;1&#xff09;设置一个按钮 &#xff08;2&#xff09;右键按钮&#xff0c;选择样式表 &#xff08;3&#xff09;编写全局样式 font-size 设置字体大小&#xff1b; border-radius 设置圆角矩形&#xff1b; background-color 设置…

数据结构-树(基础,分类,遍历)

数据结构-树 1.什么是树&#xff1f; 在计算机科学中&#xff0c;树是一种常用的非线性数据结构&#xff0c;用于表示具有层次关系的数据。与线性数据结构&#xff08;如数组和链表&#xff09;不同&#xff0c;树结构以节点&#xff08;Nodes&#xff09;和边&#xff08;Ed…

日元走强引领外汇市场新动向,全球经济指标波动加剧

日元看涨情绪升温 近期&#xff0c;外汇市场上日元成为焦点&#xff0c;对冲基金纷纷增加对日元上涨的期权投注&#xff0c;预计其将延续本季度强劲表现。上周五&#xff0c;美元兑日元收跌0.65%&#xff0c;盘中触及年内低点&#xff0c;显示出市场对日元未来走势的乐观预期。…

一文了解什么是TTP — 技术、战术与程序

导语&#xff1a;TTP的概念最早来自于军事领域及反恐活动&#xff0c;后面逐渐被应用到网络安全领域&#xff0c;在网络安全中&#xff0c;TTP&#xff08;技术、战术与程序&#xff09;是一个核心概念&#xff0c;它涵盖了攻击者使用的工具、技术和方法&#xff0c;以及他们执…

HTML+CSS - 网页布局之多列布局定位

1. 多列布局 CSS中多列布局处理文本内容&#xff0c;特别适合对于长段落或者大量文本进行自动分栏显示 类似于grid分布&#xff0c;但相较之下更加简洁明了 基本语法 <div class"container"><p>这是一些示例文本&#xff0c;当我们使用 column-count…

SpringBoot Kafka发送消息与接收消息实例

前言 Kafka的基本工作原理 我们将消息的发布&#xff08;publish&#xff09;称作 producer(生产者)&#xff0c;将消息的订阅&#xff08;subscribe&#xff09;表述为 consumer&#xff08;消费者&#xff09;&#xff0c;将中间的存储阵列称作 broker(代理)&#xff0c;这…

酷炫的航模直升机技术详解

1. 分类与级别&#xff08;400级至90级&#xff09; 航模直升机以其独特的飞行魅力和高难度的操作技巧&#xff0c;吸引了众多飞行爱好者。根据模型的尺寸、重量、动力系统及飞行性能&#xff0c;航模直升机大致可分为多个级别&#xff0c;从入门级的400级到专业级的90级及以上…

简单接口自动化框架实现(Python+requests+pytest)

1、接口自动化流程 1.需求分析2.挑选需要做自动化测试的功能3.设计测试用例4.搭建自动化测试环境[可选]5.设计自动化测试项目的架构[可选]6.编写代码7.执行测试用例8.生成测试报告并分析结果 2、框架结构 --api -->封装请求 --scripts -->编写测试脚本…

15. Springboot集成Redis

目录 1、前言 2、为什么选择Spring Boot集成Redis&#xff1f; 3、快速上手 3.1、引入依赖 3.2、 配置连接信息 3.3、自定义配置类 4、RedisTemplate的使用 4.1、String类型操作 4.2、 Hash类型操作 4.3、List类型操作 4.4、Set类型操作 4.5、SortedSet类型操作 4…

有了数据中台,是否需要升级到数据飞轮?怎么做才能升级到数据飞轮?

在数字化转型的时代&#xff0c;企业纷纷建设了“数据中台”&#xff0c;把各种业务数据整合在一起&#xff0c;仿佛是将所有材料都整理进了厨房的储物柜。 但是问题是&#xff1a;光有储物柜&#xff0c;能做出好吃的菜吗&#xff1f;答案显然是否定的。想要真正利用这些数据…

华为HarmonyOS地图服务 -- 如何实现地图呈现?-- HarmonyOS自学8

如何使用地图组件MapComponent和MapComponentController呈现地图&#xff0c;效果如下图所示。 MapComponent是地图组件&#xff0c;用于在您的页面中放置地图。MapComponentController是地图组件的主要功能入口类&#xff0c;用来操作地图&#xff0c;与地图有关的所有方法从此…

项目实现:云备份③(配置文件加载模块、数据管理模块的实现)

云备份 前言配置文件加载模块配置信息的设计单例文件配置类设计 数据管理模块数据信息类设计数据管理类实现数据持久化存储初始化加载实现 前言 书接上回&#xff1a;云备份&#xff08;实用工具类&#xff09;实现后&#xff0c;接下来会逐步实现不同模块的功能。会频繁用到工…

更主动的对话规划者:PPDPP论文解读

摘要 主动对话在大语言模型&#xff08;LLMs&#xff09;时代中是一个实际且具有挑战性的对话问题&#xff0c;其中对话策略规划是提升LLMs主动性的重要关键。现有的大多数研究通过各种提示方案或使用口头AI反馈迭代增强处理特定案例的能力&#xff0c;以实现LLMs的对话策略规…

元宇宙+教育:打造个性化、互动化学习生态系统!

近两年来&#xff0c;元宇宙风在全球迅速掀起了一股新浪潮。“元宇宙”成为各个行业的热门发展方向&#xff0c;各个行业正试图通过元宇宙寻求新的发展突破口&#xff0c;教育行业也不例外。 教育培训元宇宙作为一种前沿的教育模式&#xff0c;深度融合了虚拟现实、增强现实及…

SAP HCM HR_MAINTAIN_MASTERDATA自带解锁功能

导读 锁功能&#xff1a;在SAP HCM模块有针对人的加锁功能&#xff0c;今天遇到的一个问题是&#xff0c;人员无法被锁住&#xff0c;给我第一反应就是代码没有加锁&#xff0c;代码有问题&#xff0c;但是去看代码系统确实已经加锁&#xff0c;但是系统还是提示这个&#xff…

BPF 调度器 sched_ext 实现机制、调度流程及样例

本文地址&#xff1a;https://www.ebpf.top/post/bpf_sched_ext_dive_into 在文章 Linus 强势拍板合入: BPF 赋能调度器终成正果中&#xff0c;我们回顾了 BPF 在调度器在合入社区过程中的历程&#xff0c;补丁 V7 已经在为合并到 6.11 做好了准备&#xff0c;后续代码仓库也变…

4. 认识 LoRA:从线性层到注意力机制

如果你有使用过 AI 生图&#xff0c;那你一定对 LoRA 有印象&#xff0c;下图来自Civitai LoRA&#xff0c;上面有很多可供下载的LoRA模型。 你可能也曾疑惑于为什么只导入 LoRA 模型不能生图&#xff0c;读下去&#xff0c;你会解决它。 文章目录 为什么需要 LoRA&#xff1f;…

预训练数据指南:衡量数据年龄、领域覆盖率、质量和毒性的影响

前言 原论文&#xff1a;A Pretrainer’s Guide to Training Data: Measuring the Effects of Data Age, Domain Coverage, Quality, & Toxicity 摘要 预训练是开发高性能语言模型&#xff08;LM&#xff09;的初步和基本步骤。尽管如此&#xff0c;预训练数据的设计却严…