vector使用

news2024/11/17 0:21:54

文章目录

  • vector的介绍
  • vector的使用
    • vector的初始化
    • vector iterator迭代器的使用
    • vector 空间增长问题
    • vector的增删改查
  • 迭代器失效
  • 总结


vector的介绍

文档介绍

  1. vector是表示可变大小数组的序列容器。
  2. 就像数组一样,vector也采用的连续存储空间来存储元素。也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效。但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。
  3. 本质讲,vector使用动态分配数组来存储它的元素。当新元素插入时候,这个数组需要被重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将全部元素移到这个数组。就时间而言,这是一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。
  4. vector分配空间策略:vector会分配一些额外的空间以适应可能的增长,因为存储空间比实际需要的存储空间更大。不同的库采用不同的策略权衡空间的使用和重新分配。但是无论如何,重新分配都应该是对数增长的间隔大小,以至于在末尾插入一个元素的时候是在常数时间的复杂度完成的。
  5. 因此,vector占用了更多的存储空间,为了获得管理存储空间的能力,并且以一种有效的方式动态增长。
  6. 与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list统一的迭代器和引用更好。

vector的使用

下面是对于vector的基本用法的讲解

vector的初始化

(constructor)构造函数声明接口说明
vector()(重点)无参构造
vector(size_type n, const value_type& val = value_type())构造并初始化n个val
vector (const vector& x); (重点)拷贝构造
vector (InputIterator first, InputIterator last);使用迭代器进行初始化构造

主要使用的是无参构造和拷贝构造,其他两种不常用,下面代码一并介绍

void test1()
{
	//1.vector()(重点) | 无参构造 
	vector<int> v1;
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);
	for (auto c : v1)
	{
		cout << c << " ";
	}
	cout << endl;

	//2.vector(size_type n, const value_type& val = value_type()) | 构造并初始化n个val
	vector<int> v2(10, 0);
	for (auto c : v2)
	{
		cout << c << " ";
	}
	cout << endl;

	//3.vector(const vector & x); (重点) | 拷贝构造        
	vector<int> v3(v1);
	for (auto c : v3)
	{
		cout << c << " ";
	}
	cout << endl;

	//4.vector(InputIterator first, InputIterator last);
	vector<int> v4(v2.begin(), v2.end());
	for (auto c : v4)
	{
		cout << c << " ";
	}
	cout << endl;
}
int main()
{
	test1();
	return 0;
}

在这里插入图片描述

vector iterator迭代器的使用

vector的迭代器有两种,正向和反向迭代器

正向:begin() 和 end() 分别表示获取第一个数据的位置,获取最后一个数据的下一个位置

反向:rbegin() 和 rend() 分别表示获取最后一个数据的位置,获取第一个元素的前一个位置

//迭代器的名称分别为  iterator  和reverse_iterator
void test2()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	//auto rit=v.rbegin();
	vector<int>::reverse_iterator rit = v.rbegin();
	while (rit != v.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;
	for (auto c : v)
	{
		cout << c << " ";
	}
	cout << endl;
}
int main()
{
	test2();
	return 0;
}

在这里插入图片描述

vector 空间增长问题

使用几种函数来管理和查看vector的空间

容量空间接口说明
size获取数据个数
capacity获取容量大小
empty判断是否为空
resize改变vector的size
reserve改变vector的capacity

主要是对于resize和reserve的使用,empty就是判别是否为空,size和capacity是查看当前vector的数据个数和容量

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

	cout << v.size() << endl;
	cout << v.capacity() << endl;

	v.resize(20);
	cout << "更改size为20" << endl;
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	v.reserve(40);
	cout << "更改capacity为40" << endl;
	cout << v.size() << endl;
	cout << v.capacity() << endl;


	v.resize(50);
	cout << "更改size为50" << endl;
	cout << v.size() << endl;
	cout << v.capacity() << endl;
}
void test4()
{
	vector<int> v;
	size_t ans = v.capacity();
	for (int i = 0; i < 200; i++)
	{
		v.push_back(i);
		if (ans != v.capacity())
		{
			cout << "capacity为:" << ans << endl ;
		}
		ans = v.capacity();
	}
}

int main()
{
	test4();
	return 0;
}

在这里插入图片描述

注意:capacity的增长倍数是由环境决定的,vs下在1.5倍数左右,在Linux下近乎2倍,且关于resize和reserve,我们只需要知道resize底层是调用reserve的,满足size<=capacity

vector的增删改查

vector的增删改查接口说明
push_back尾插
pop_back尾删
find查找指定的数据,返回下标(在算法模块,不在vector的成员函数中)
insert在pos位置上插入指定数值val
erase删除指定pos位置上的数据
swap交换两个vector对象的数据空间
operator[ ]和数组一样,通过下标方括号来访问vector的数据

STL分为两大模块,容器和算法,容器例如vector、list、set等,算法是在头文件<algorithm>中,是将容器中通用的函数归档在<algorithm>中,按照迭代器的不同,不同容器能使用相同或不同的函数。

push_back 和 pop_back 以及operator[ ]的使用

简单理解,不必做详解

void test5()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	//push_back的使用,传参val   const value_type& val  value_type实际就是T 模板类
	for (auto c : v)
	{
		cout << c << " ";
	}
	cout << endl;
	//pop_back 的使用,不必传参,尾删
	v.pop_back();   
	for (auto c : v)
	{
		cout << c << " ";
	}
	cout << endl;
	//operator[]的使用   可以访问指定下标位置元素,也可赋值
	cout << v[2] << endl;
	v[2] = 10;
	cout << v[2] << endl;
}
int main()
{
	test5();
	return 0;
}

find

在<algorithm>算法中,InputIterator find (InputIterator first, InputIterator last, const T& val);

#include<algorithm>
void test6()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	auto it =find(v.begin(), v.end(), 5);
	if (it != v.end())
	{
		cout << *it << endl;
	}
	else if(it == v.end())
	{
		cout << "没有找到val,返回的是v.end()" << endl;
	}
}
int main()
{
	test6();
	return 0;
}

在这里插入图片描述

insert

insert的插入,实际上就是先得到要插入的数值个数n,然后将vector中的元素后移n位,然后依次填入插入的数据

在这里插入图片描述

void test7()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	for (auto c : v)
	{
		cout << c << " ";
	}
	cout << endl;
	//1.iterator insert (iterator position, const value_type& val); 
	auto it=v.insert(v.begin() + 1, 10);
	cout << "返回迭代器指向的数值为:" << *it << endl;
	for (auto c : v)
	{
		cout << c << " ";
	}
	cout << endl;

	//2.void insert (iterator position, size_type n, const value_type& val);
	v.insert(v.begin(), 5, 6);
	for (auto c : v)
	{
		cout << c << " ";
	}
	cout << endl;

	//3.void insert(iterator position, InputIterator first, InputIterator last);
	v.insert(v.begin(), v.begin(), v.end());
	for (auto c : v)
	{
		cout << c << " ";
	}
	cout << endl;

	vector<int> v1;  //后两个参数,只要是迭代器即可,可以是其他容器的迭代器数据插入过来
	v1.insert(v1.begin(), v.begin(), v.begin()+6);
	for (auto c : v1)
	{
		cout << c << " ";
	}
	cout << endl;

}
int main()
{
	test7();
	return 0;
}

erase

在这里插入图片描述

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

	//指定pos迭代器删除
	auto it =v.erase(v.begin());  //返回的是删除之后的v.begin()
	cout << *it << endl;
	for (auto c : v)
	{
		cout << c << " ";
	}
	cout << endl;  
	//区间删除
	it=v.erase(v.begin() + 1, v.begin()+2);
	cout << *it << endl;		//返回的是删除之后的v.begin() + 1   但是要注意越界问题
	for (auto c : v)
	{
		cout << c << " ";
	}
	cout << endl;
}
int main()
{
	test8();
	return 0;
}

迭代器失效

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,所以迭代器失效实际上就是迭代器底层对应指针所指向的空间被销毁了,而使用一窥啊已经倍释放的空间,当继续使用已经失效的迭代器,会造成程序崩溃。

迭代器失效的情景

  • 引起底层空间的改变都有可能是造成迭代器失效,如resize、reserve、insert、push_back等。他们的同意特性就是会在底层调用reserve来判断增加元素时,是否需要扩容。
  • 指定位置元素的删除操作,erase(pos)

第一种场景,统一导致迭代器失效的是,由于增加元素或者手动扩容,导致vector扩容,然而扩容机制,底层是新建一个T指针数组,拷贝原有数据到新数组中,然后释放原来的数组空间,所以迭代器会失效(此时的迭代器指向的是一块被释放的空间),导致程序崩溃

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

	//底层的改变实际上就是是否扩容了
	
	//先获得当前vector的首元素的迭代器
	vector<int>::iterator it = v.begin();  
	cout << *it << endl;
	//1.如果经历了resize ,触发扩容,迭代器失效    代码为 -1073741819。
	//v.resize(50, 0);
	//cout << *it << endl;
	
	//2.如果使用reserve手动扩容的话,也会导致迭代器失效
	//v.reserve(100);
	//cout << *it << endl;  //代码为 -1073741819。

	//3.如果是插入元素,导致扩容,也会导致迭代器失效
	//v.insert(v.begin(), 100, 1);
	//cout << *it << endl;    //代码为 -1073741819。

	//4.如果是push_back 导致扩容,也会发生迭代器失效
	for (int i = 0; i < 100; i++)
	{
		v.push_back(i);
	}
	cout << *it << endl;   //代码为 -1073741819。
}
int main()
{
	test9();
	return 0;
}

第二种场景,erase函数,删除指定pos位置数据,或者删除迭代器区间的数据。我们先用auto it=v.begin()+5,获得迭代器,然后我们删除一个元素,删除之后有两种可能:1.it指向的位置还有元素,那么按照道理来说 cout一下还是能正常输出数值 2.it位置已经没有元素了,此时it指向的空间已经是vector.end()之后了,再次访问it的时候,就会报错,相当于越界了。

综合上述两种可能,因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了。

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

	auto it = v.begin();
	v.erase(v.begin());
	//v.erase(v.begin(), v.end());
	cout << *it << endl;  //代码为 -1073741819
}
int main()
{
	test10();
	return 0;
}

迭代器失效解决办法:在使用前,对迭代器重新赋值即可。

总结

vector的优点:

1.支持随机访问(以[]的方式)

2.cpu高速缓存效率高

vector的缺点:

1.中间和头部删除元素效率低(要移动数组元素)

2.扩容问题(扩容会导致迭代器失效)

总结:

  • vector的使用实际上大部分的函数与string中的用法相似,我们只需要知道一点的是,vector是一个可变长的连续有序序列即可,不管是空间还是物理上,数据是连续的。
  • vector的初始的capacity的大小和初始化的数据个数有关,然后依次为基点,在VS平台以近似1.5倍扩容,在Linux下以2倍扩容。
  • 在vector中我们初步认识到了<algorithm>的存在,这是算法,包含在STL中,STL分为容器和算法,<algorithm>中是总结所有容器所需要的接口,通过迭代器来实现。不同的容器有不同的迭代器,能实现不同的算法接口。
  • 迭代器失效问题,是string以及vector在涉及到扩容或者erase中会发生的问题,但是erase返回参数为iterator,所以只需要再次赋值即可,而扩容导致的迭代器失效,我们只能再次对迭代器重新赋值,取得新的迭代器。随用随取,在使用前,对迭代器重新赋值。
  • 综上,我们可以通过vector,不必顾忌数组的长度问题,通过相应的便捷的接口,来实现更多可能性的操作。

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

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

相关文章

分布式事务及解决方案

1、分布式事务 分布式事务就是在一个交易中各个服务之间的相互调用必须要同时成功或者同时失败&#xff0c;保持一致性和可靠性。在单体项目架构中&#xff0c;在多数据源的情况下也会发生 分布式事务问题。本质上来说&#xff0c;分布式事务就是为了保证不同数据库的数据一致性…

关于Docker的知识点

Docker是一个快速交付应用、运行应用的技术。 Docker基本操作--容器 示例&#xff1a;创建运行一个Nginx容器

【每日一题】—— B - Broken Rounding(AtCoder Beginner Contest 273)

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;每日一题 &#x1f48c;其他专栏&#xff1a; &#x1f534; 每日反刍 &#x1f7e1; C跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0c;缓称…

【个人笔记】Linux命令之watch命令

1.命令简介 watch 以周期性方式执行给定的命令&#xff0c;并全屏显示执行结果&#xff0c;可以帮助监测一个命令的运行结果。 2.命令格式及参数选项说明 命令格式&#xff1a; watch [OPTIONS] COMMAND选项说明&#xff1a; -d, --differences [PERMANENT]高亮显示最近两…

Ventoy 使用教程图文详细版

文章目录 Ventoy 使用教程图文详细版简介安装 Ventoy下载 Ventoy安装到 U盘使用 Ventoy复制 ISO 文件启动电脑选择 ISO 文件结论Ventoy 使用教程图文详细版 简介 Ventoy 是一款开源的 U盘 启动工具,设计用于简化从 U盘 启动操作系统的过程。其主要特点是支持直接使用 ISO 文…

怎么绘制简爱思维导图?用这个工具绘制很简单

怎么绘制简爱思维导图&#xff1f;绘制思维导图是一项非常有用的技能&#xff0c;有助于梳理思路、整理知识、更好地理解和记忆信息。因此&#xff0c;无论你是学生、教师、工程师、项目经理或者只是想要更好地组织自己的想法&#xff0c;学会绘制思维导图都是非常有益的。下面…

吃透《西瓜书》第三章 线性模型:多元线性回归

&#x1f349; 吃瓜系列 教材&#xff1a;《机器学习》 周志华著 &#x1f552;时间&#xff1a;2023/7/26 目录 一、多元线性回归 1 向量化 1.1.1 向量化 1.1.2 使用最小二乘法构建损失函数 1.1.3 去除求和符号&#xff0c;改成向量点乘的形式 1.1.4 数学原理 2 求解…

机器学习笔记之优化算法(二)线搜索方法(方向角度)

机器学习笔记之优化算法——线搜索方法[方向角度] 引言回顾&#xff1a;线搜索方法从方向角度观察线搜索方法场景构建假设1&#xff1a;目标函数结果的单调性假设2&#xff1a;屏蔽步长 α k \alpha_k αk​对线搜索方法过程的影响假设3&#xff1a;限定向量 P k \mathcal P_k …

9. Spring MVC

目录 1. Spring MVC 介绍 1.1 MVC 定义 1.2 MVC 和 Spring MVC 的关系 1.3 Spring、Spring Boot 和 Spring MVC 的关系 2. Spring MVC 的创建和连接 2.1 Spring MVC 项目返回视图 2.2 Spring MVC 项目返回数据 2.3 RequestMapping 是 post 还是 get 请求 3. 获取参数…

PX4固件报错“Accel 0 clipping, not safe to fly!“

最近在使用PX4固件时&#xff0c;遇到了报错&#xff1a; “Accel 0 clipping, not safe to fly!” 这个报错我以前是从没遇到过的&#xff0c;可见是新版固件才会有的。 正常来说&#xff0c;只有山寨乞丐版飞控才会经常出现这类传感器的报错。 但是我手里的是5000多的X7 pro&…

使用多数据源dynamic-datasource-spring-boot-starter遇到的问题记录

记录使用多数据源dynamic-datasource-spring-boot-starter遇到的问题&#xff1a; 1、工程启动失败 缺少clickhouse连接驱动&#xff0c;引入对应的maven依赖 <!--ck连接驱动--><dependency><groupId>ru.yandex.clickhouse</groupId><artifactId>…

没有颜值插件的编辑器是没有灵魂的--【idea-theme插件】

文章目录 本系列校训idea安装程序员常用软件工具推荐1.JetBrains全家桶2.Microsoft Visual Studio3.eclise 系列 先看一下VS Code 的特色idea 系列 的颜值插件idea插件安装Material_ThemeMaterail 家自己的themes主题免费的版本在前面 本系列校训 颜值即正义&#xff01;你漂亮…

浅谈性能测试中的基准测试

在性能测试中有一种测试类型叫做基准测试。这篇文章&#xff0c;就聊聊关于基准测试的一些事儿。 1、定义 通过设计合理的测试方法&#xff0c;选用合适的测试工具和被测系统&#xff0c;实现对某个特定目标场景的某项性能指标进行定量的和可对比的测试。 2、特质 ①、可重…

SUI供应量等问题的说明以及终止与MovEX的合作声明

原生加密token是区块链经济系统的基石&#xff0c;对网络的安全、运作和增长至关重要。Sui的原生token SUI有如下四个关键用途&#xff1a; 质押给验证节点&#xff0c;以确保网络的安全&#xff0c;并赚取质押奖励用于支付gas费&#xff0c;以执行交易和其他操作作为原生资产&…

用python怎么输出个人信息,python怎么输出个人信息

大家好&#xff0c;给大家分享一下python输入自己的姓名,输出hello,某某某同学&#xff0c;很多人还不知道这一点。下面详细解释一下。现在让我们来看看&#xff01; 1、python要求用户输入姓名并输出 name input("请输入姓名:") print("你好,"&#xff…

MSFCS互相联动

MSF&CS互相联动 1. 前言2. CS联动MSF2.1. 案例测试2.1.1. CS设置联动监听器2.1.2. CS设置联动MSF会话2.1.3. MSF设置监听 3. MSF联动CS3.1. 案例测试3.1.1. MSF生成木马3.1.2. 设置监听3.1.3. CS设置监听3.1.4. MSF转移会话3.1.5. 查看上线 4. 其它 1. 前言 在日常渗透测试…

【单片机】温控系统参数辨识及单片机PID控制

温控系统参数辨识及单片机PID控制 1. 温控系统组成2. matlab辨识系统参数2.1 采集阶跃响应信号导入matlab系统辨识模块 PID控制 1. 温控系统组成 半导体制冷片正向通电制冷&#xff0c;反向通电制热。系统采用半导体制冷片&#xff08;帕尔贴&#xff09;作为执行单元&#xf…

使用adb通过电脑给安卓设备安装apk文件

最近碰到要在开发板上安装软件的问题&#xff0c;由于是开发板上的安卓系统没有解析apk文件的工具&#xff0c;所以无法通过直接打开apk文件来安装软件。因此查询各种资料后发现可以使用adb工具&#xff0c;这样一来可以在电脑上给安卓设备安装软件。 ADB 就是连接 Android 手…

C++中对 this 指针的理解

引出 我们首先了解this指针&#xff0c;要先了解class&#xff08;类&#xff09;&#xff0c;类其实就相当于C语言中的结构体一样&#xff0c;也是创建了一个自定义类型。对于类而言该类型下面可以存放成员函数&#xff0c;成员变量。类可以声明一个变量&#xff0c;对该变量…

数据结构---LRU CACHE

什么是LRU 通过之前的学习我们知道计算机在处理任务的时候是先将数据从硬盘中提取出来加载进内存&#xff0c;然后再将内存中的数据加载进入cpu进行计算&#xff0c;但是这里存在一个问题cpu的计算速度非常快&#xff0c;而内存中加载数据的速度又很慢&#xff0c;所以为了提供…