【C++初阶】第九站:vector的介绍及使用

前言:

🎯个人博客:Dream_Chaser

🎈博客专栏:C++

📚本篇内容:vector的介绍及使用

目录

一、vector的介绍

二、vector的使用

1.vector的定义

2.vector iterator(迭代器)的使用

begin和end(正向迭代器)

rbegin和rend(反向迭代器)

3.vector 空间增长问题

size和capacity

max_size

reserve和resize

empty

4.vector 增删查改

push_back和pop_back

insert

find

erase

clear 和 shrink_to_fit


一、vector的介绍

1.1 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的文档介绍,vector在实际中非常的重要,在实际中我们熟悉常见的接口就可以,下面列出了哪些接口是要重点掌握的。

1.vector的定义

方式一:创建一个空的整数容器v1,不包含任何元素

vector<int> v1;

方式二:创建一个包含10个初始值为0的整数的容器v2

vector<int> v2(10, 0);

方式三:创建一个容器v3,其元素是通过复制v2容器的起始位置到结束位置的元素而来(v3包含了v2的所有元素)

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

方式四:创建一个整数容器v4,其元素是通过将字符串s的字符转换为对应的ASCII码并复制而来

字符串迭代器在此上下文中会依次指向每个字符,因此v4包含了s中每个字符的ASCII值

// 创建一个字符串s,内容为"hello world"
string str("hello world");
vector<int> v4(str.begin(),str.end());

方式五: v5通过拷贝构造函数初始化,包含与v4相同的元素

vector<int> v5(v4);// 创建一个容器v5,它是容器v4的一个副本

2.vector iterator(迭代器)的使用

for循环的遍历方式

void test_vector1()
{
	vector<int> v1;
	vector<int> v2(10, 0);
	vector<int> v3(v2.begin(), v2.end());
    //for循环遍历
	for (size_t i = 0; i < v3.size(); i++)
	{
		cout << v3[i] << " ";
	}
	cout << endl;
}
int main()
{
	test_vector1();
}

begin和end(正向迭代器)

begin函数返回指向容器内第一个元素的迭代器,end函数返回指向vector容器中末尾元素的下一个位置的迭代器。

正向迭代器遍历容器:

#include<iostream>
#include<vector>
using namespace std;
void test_vector1()
{
	string str("hello world");
	vector<int> v4(str.begin(),str.end());
	vector<int>::iterator it = v4.begin();
//	auto it = v4.begin();
	while (it != v4.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}

rbegin和rend(反向迭代器)

rbegin:返回一个指向容器中的最后一个位置的元素的迭代器

rend:返回一个指向容器中的第一个位置的元素的前一个元素的迭代器

反向迭代器遍历容器:

#include<iostream>
#include<vector>
using namespace std;
void test_vector1()
{
    vector<int>::reverse_iterator rit = v4.rbegin();
    while (rit != v4.rend())
    {
	    cout << *rit << " ";
	    ++rit;
    }
}

范围for方式遍历

void test_vector1()
{
	string str("hello world");
	vector<int> v4(str.begin(),str.end());
	vector<int> v5(v4);
	for (auto e : v5)
	{
		cout << e << " " ;
	}
	cout << endl;
}

3.vector 空间增长问题

size和capacity

通过size函数获取当前容器中的有效元素个数,通过capacity函数获取当前容器的最大容量。

#include <iostream>
#include <vector>
using namespace std;

int main()
{
	vector<int> v(10, 2);
	cout << v.size() << endl; //获取当前容器中的有效元素个数
	cout << v.capacity() << endl; //获取当前容器的最大容量
	return 0;
}

vs2019和g++扩容机制的对比:

//在两种不同的编译器下使用相同的代码
#include<iostream>
#include<vector>
using namespace std;
void test_vector2()
{
	size_t sz;
	vector<int> v;
	sz = v.capacity();
	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<<endl;
		}
	}
}
int main()
{
	test_vector2();
}

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

max_size

是一个固定的值:

reserve和resize

reserve函数改变容器的最大容量,resize函数改变容器中的有效元素个数

reserve规则:

n>capacity:如果n大于当前容器的容量,该函数使容器重新分配存储空间,将其容量增加到n(或更大)。

n <= capacity:其他情况来说,该函数不会影响容器重新分配存储空间和容器的容量不会受到影响。

该函数不会影响容器的有效数据个数(size)和不会改变它原本的元素。

如果说需要提前开好空间,避免频繁扩容,就可以使用reserve函数:
// 如果已经确定vector中要存储元素大概个数,可以提前将空间设置足够
// 就可以避免边插入边扩容导致效率低下的问题了
void test_vector2()
{
	size_t sz;
	vector<int> v;
	v.reserve(100); // 提前将容量设置好,可以避免一遍插入一遍扩容
	sz = v.capacity();
	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<<endl;
		}
	}
}
  • reserve 只负责开辟空间,如果确定知道需要用多少空间, reserve 可以缓解 vector 增容的代价缺陷问题。
以下这种情况 可以访问吗

不能,这里虽然空间是开出来了,但不能访问,原因是这个[ ]里面加了个断言,访问的下标必须是小于size,(此时的size应该为0,因为reserve不改变size),顺序表与数组有个区别,有个规定:你的数据必须是0到size-1,访问数据时是连续访问的,所以你只能访问0 - size-1的数据,报错就报在这个断言上面了:

那我要想访问这个数据怎么办呢?换成resize。

resize规则:

n < size:如果n小于当前容器的有效数据个数,它的内容被简化为前n个元素,移除后面的元素(并
摧毁它们)
n>size:如果n大于当前容器的有效数据个数,它的内容通过在末尾插入尽可能多的元素来扩展内容,使其大小达到n

如果指定了val,那么新添加的元素将被初始化为val的副本;否则,它们将进行值初始化。

如果n也大于当前容器的capacity,则会自动重新分配已分配的存储空间。

请注意,此函数通过插入或删除元素来改变容器的实际内容。

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

empty

通过empty函数判断当前容器是否为空。

4.vector 增删查改

push_back和pop_back

push_back:在容器的最后一个元素之后添加一个新元素。将val的内容复制(或移动)到新元素中。

pop_back:删除容器中的最后一个元素,有效地将容器大小减少1。

void test_vector4()
{
	vector<int> v;
	v.push_back(4);
	v.push_back(3);
	v.push_back(2);
	v.push_back(1);
	//使用范围for遍历
	cout << "遍历:" << endl;
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
    v.pop_back();
	for (auto e : v)
	{
		cout << e << " ";
	}
}

insert

insert:通过在指定位置的元素之前插入新元素,可以有效地增加容器的大小。

void test_vector4()
{ 
    cout << "头插:" << endl;
	v.insert(v.begin(),0);//头插
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

find

返回范围[first,last)中与val相等的第一个元素的迭代器。如果没有找到这样的元素,则返回last。

如果说此时我要在3前面插入一个元素,我们可以发现vector没写对应的find,但是我们可以在全局(algorithm)找到一个find,这对于string、vector、list等容器都是通用的,只是说可能string的需求更复杂一点,需要单独去给string实现它的find。

test_vector4(){    
    cout << "在值为3前面的位置插入值为30的元素:";
	auto it = find(v.begin(),v.end(),3);//这里返回的指向3这个元素的的位置的迭代器
	if (it != v.end())
	{	//在下标为3的位置插入
		v.insert(it,30);//把元素3挤到后面一个位置
	}
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

erase

erase:从容器中删除一个元素(位置)或一个元素范围([第一,最后)]。

test_vector4()
{
    cout << "删除值为3的元素:";
	//返回值指向值为3的元素的迭代器,此迭代器指向了元素为3的这个位置
	it = find(v.begin(),v.end(),3);//下标为2
 	if (it != v.end())
	{
		v.erase(it);//it=2
	}
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

clear 和 shrink_to_fit

本章完。

🔧本文修改次数:0

🧭更新时间:2024年4月5日 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第十届蓝桥杯大赛个人赛省赛(软件类) CC++ 研究生组2.0

A立方和 #include<iostream> #include<cmath> using namespace std; int main(){int n, t, flag, x;long long ans 0;for(int i 1; i < 2019; i){t i;flag 0;while(t && !flag){x t % 10;if(x 2 || x 0 || x 1 || x 9) flag 1;t / 10;}if(fl…

基于圆柱体镜子和光线跟踪实现镜反射观测全景观图的matlab模拟仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 光线与圆柱镜面的交点计算&#xff1a; 反射光线计算&#xff1a; 全景图坐标转换&#xff1a; 5.完整程序 1.程序功能描述 基于圆柱体镜子和光线跟踪实现镜反射观测全景观图.模拟的场景…

ISTQB选择国内版,还是国际版呢

1, ISTQB简介 ISTQB&#xff08;International Software Testing Qualifications Board&#xff09;是一个国际软件测试资格认证机构&#xff0c;旨在提供一个统一的软件测试认证标准。ISTQB成立于2002年&#xff0c;是非盈利性的组织&#xff0c;由世界各地的国家或地区软件测…

case语句

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 CASE 语句的执行方式与 IF...THEN...ELSIF 语句的执行方式类似&#xff0c;但是它是通过一个表达式的值来决定执行哪个分支 CASE 选择器表达式 WHEN 条件 1 THEN 语句序列 …

从多模态生物图数据中学习Gene的编码-MuSeGNN

由于数据的异质性&#xff0c;在不同的生物医学背景下发现具有相似功能的基因对基因表示学习提出了重大挑战。在本研究中&#xff0c;作者通过引入一种称为多模态相似性学习图神经网络的新模型来解决这个问题&#xff0c;该模型结合了多模态机器学习和深度图神经网络&#xff0…

Linux gcc day3

find命令&#xff08;importance&#xff09;&#xff1a; 语法&#xff1a;find pathname -options find /root -name test.c which命令&#xff1a; which [指令] 只搜索指令&#xff0c;在什么位置下 为什么文件夹带有颜色呢&#xff1f; 科普补充alias命令&#xff1a; ali…

redis的简单操作

redis中string的操作 安装 下载可视化软件&#xff1a;https://gitee.com/qishibo/AnotherRedisDesktopManager/releases。 Mac安装redis&#xff1a; brew install redisWindows安装redis: 安装包下载地址&#xff1a;https://github.com/tporadowski/redis/releases 1.…

C语言进阶课程学习记录-第20课 - 链接过程简介

C语言进阶课程学习记录-第20课 - 链接过程简介 链接器静态链接实验-静态链接源代码生成目标文件打包生成静态库文件直接编译使用静态库编译 动态链接实验-动态链接源代码生成动态链接库文件直接编译使用动态链接库编译运行test.out删除dlib.so运行test.out 小结 本文学习自狄泰…

[LeetCode][LCR133]位 1 的个数——快速从右边消去1

题目 LCR 133. 位 1 的个数 编写一个函数&#xff0c;输入是一个无符号整数&#xff08;以二进制串的形式&#xff09;&#xff0c;返回其二进制表达式中数字位数为 ‘1’ 的个数&#xff08;也被称为 汉明重量).&#xff09;。 提示&#xff1a; 请注意&#xff0c;在某些语言…

静态路由协议实验1

要求&#xff1a; 使用静态路由协议使得全网可达。 第一步、规划IP地址。并配置IP。 第二步、写静态路由 [r1]ip route-static 192.168.3.0 24 192.168.2.2 [r1]ip route-static 192.168.4.0 24 192.168.2.2 [r1]ip route-static 192.168.5.0 24 192.168.2.2[r2]ip route-st…

计算机中丢失steam_api64.dll怎么办?七个方法教你轻松解决

在计算机使用过程中&#xff0c;我们经常会接触到各种各样的动态链接库&#xff08;DLL&#xff09;文件。其中&#xff0c;steamapi64.dll是Steam游戏平台中的一个关键组件&#xff0c;它为Windows操作系统带来了许多好处。本文将详细介绍steamapi64.dll对Windows的好处以及其…

用顺序表实现通讯录

前言 这次的通讯录是基于上一篇的动态顺序表的基础上实现的&#xff0c;如果对动态顺序表不熟悉&#xff0c;可以打开这个链接阅读http://t.csdnimg.cn/9zJ5g&#xff0c;这里我们会调用动态顺序表的函数。 如果想看静态顺序表实现通讯录&#xff0c;可以打开这个链接阅读http:…

thinkphp6入门(21)-- 如何删除图片、文件

假设文件的位置在 /*** 删除文件* $file_name avatar/20240208/d71d108bc1086b498df5191f9f925db3.jpg*/ function deleteFile($file_name) {// 要删除的文件路径$file app()->getRootPath() . public/uploads/ . $file_name; $result [];if (is_file($file)) {if (unlin…

Vite 项目中环境变量的配置和使用

Vite 项目中环境变量的声明 我们要在 Vite 项目中进行环境变量的声明&#xff0c;那么需要在项目的根目录下&#xff0c;新建 .env.[mode] 文件用于声明环境变量&#xff0c;如&#xff1a; .env.test 文件用于测试环境下项目全局变量的声明.env.dev 文件用于开发环境下项目全…

创意绘图小程序:绘画与实用功能的完美融合

创意绘图小程序&#xff1a;绘画与实用功能的完美融合 在数字化时代&#xff0c;创意绘图小程序以其便捷性、互动性和创新性&#xff0c;成为了人们表达自我、释放创意的新平台。本文将介绍一款集白板画、黑板画功能于一身&#xff0c;同时融合画笔调整、画布清空、橡皮擦清除…

在线考试|基于Springboot的在线考试管理系统设计与实现(源码+数据库+文档)

在线考试管理系统目录 目录 基于Springboot的在线考试管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1、前台&#xff1a; 2、后台 管理员功能 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主…

C语言动态内存空间分配

1. 前言 在讲内存分配前&#xff0c;咱来聊一下为什么会有内存分配这个概念呢&#xff0c;大家都知道C语言当中是有着许多的数据类型&#xff0c;使用这些数据类型就会在内存上开辟其相对应的空间&#xff0c;那既然会开辟相应的空间&#xff0c;为什么还会有内存分配呢&#x…

【数据库】数据库的介绍、分类、作用和特点,AI人工智能数据如何存储

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《数据库》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识…

深度学习理论基础(三)封装数据集及手写数字识别

目录 前期准备一、制作数据集1. excel表格数据2. 代码 二、手写数字识别1. 下载数据集2. 搭建模型3. 训练网络4. 测试网络5. 保存训练模型6. 导入已经训练好的模型文件7. 完整代码 前期准备 必须使用 3 个 PyTorch 内置的实用工具&#xff08;utils&#xff09;&#xff1a; ⚫…

蓝桥杯 - 穿越雷区

解题思路&#xff1a; dfs 方法一&#xff1a; import java.util.Scanner;public class Main {static char[][] a;static int[][] visited;static int[] dx { 0, 1, 0, -1 };static int[] dy { 1, 0, -1, 0 };static long min Long.MAX_VALUE;static long count 0;publi…