【c++丨STL】vector的使用

news2024/12/26 21:39:51
🌟🌟作者主页:ephemerals__
🌟🌟所属专栏:C++、STL

目录

前言

vector简要介绍

一、vector的默认成员函数

构造函数(constructor)

析构函数(destructor)

赋值运算符重载operator=

二、vector的容量接口

size和capacity

resize和reserve

empty

三、vector的迭代器接口

begin和end

rbegin和rend

cbegin、cend、crbegin、crend

四、vector的元素访问接口

operator[ ]

at

front和back

五、vector的增删查改

push_back

pop_back

insert

erase

swap

clear

find

六、vector灵活运用:创建字符串数组

总结


前言

        之前我们学习了string类的使用及模拟实现,相比c语言的字符串,它的功能更强,安全性更高,操作方式更便捷。然而,在处理更复杂的数据集合时,仅仅依赖字符串往往显得力不从心,尤其是当我们需要管理一系列具有相同类型的数据项时,如一系列的数字、字符或甚至是其他字符串。这时,一个更为强大且灵活的数据结构——向量(vector)便应运而生。

        本篇文章,我们将介绍vector并深入探讨其使用方法。

vector相关接口查阅:

vector - C++ Reference

vector简要介绍

        vector是STL中的一种容器,它用于表示可变大小的数组,底层使用动态顺序表实现。相比传统的数组,vector附带了一系列操作接口,并且由于内存是动态分配的,所以不必担心插入元素时内存不足的问题。由于vector强大的功能和灵活性,我们在c++编程中经常使用vector来表示内存连续的序列。

        我们使用vector时,要引头文件<vector>,并且该容器定义在命名空间std当中。

一、vector的默认成员函数

        vector显示实现的默认成员函数如下:

构造函数(constructor)

vector一共有6个构造函数,其中最常用的有5个:

函数原型功能说明
vector();无参构造(忽略空间配置器),创建一个空的数组
vector(size_type n, const value_type& val);用n个val值构造一个对象
vector(const vector& x);拷贝构造,用对象x构造另一个vector对象
vector(InputIterator first, InputIterator last);迭代器区间构造,用一个vector对象的一部分构造另一个vector对象
vector (initializer_list<value_type> il);初始化器构造,类似于数组初始化的方式(大括号)

 代码示例:

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

void print(vector<int>& v)
{
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << ' ';
	}
	cout << endl;
}

int main()
{
	vector<int> v1;//无参构造,创建一个整形空数组
	vector<int> v2(3, 5);//n个val值构造
	vector<int> v3(v2);//拷贝构造
	vector<int> v4(v3.begin() + 1, v3.end());//迭代器区间构造
	vector<int> v5({ 1,2,3,4,5 });//初始化器构造

	print(v1);
	print(v2);
	print(v3);
	print(v4);
	print(v5);
	return 0;
}

这里需要注意:vector的本质是一个类模板,我们在定义时需要配合"< >"标明其元素类型。

析构函数(destructor)

析构函数用于释放动态分配的内存空间,在对象声明周期结束时自动调用。

赋值运算符重载operator=

赋值重载用于完成已经存在的对象的拷贝赋值。这三个赋值重载函数中,第一个和第三个比较常用:

函数原型功能说明
vector& operator=(const vector& x);将一个vector对象赋值给另一个vector对象
vector& operator=(initializer_list<value_type> il);用初始化器给对象赋值

代码示例:

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

void print(vector<int>& v)
{
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << ' ';
	}
	cout << endl;
}

int main()
{
	vector<int> v1;
	vector<int> v2({ 1,2,3,4,5 });

	v1 = v2;//将v2赋值给v1
	print(v1);

	v1 = { 5,4,3,2,1 };//初始化器赋值
	print(v1);
	return 0;
}

 

二、vector的容量接口

vector的容量接口有七个,我们介绍几个比较常用的容量接口:

size和capacity

size用于获取vector中数据元素的个数。注意:元素个数并不等同于空间容量。 

capacity用于获取当前为数组分配的空间容量,以元素表示。在任何情况下,size都小于等于capacity

不同编译器对插入元素时capacity的增长量设置可能不同,vs下基本按照1.5倍增长,而g++下按照2倍增长

代码示例:

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

int main()
{
	vector<int> v1;
	vector<int> v2(10, 1);
	vector<int> v3;
	for (int i = 0; i < 10; i++) v3.push_back(1);//插入10个元素

	cout << "v1 size:" << v1.size() << " capacity:" << v1.capacity() << endl;
	cout << "v2 size:" << v2.size() << " capacity:" << v2.capacity() << endl;
	cout << "v3 size:" << v3.size() << " capacity:" << v3.capacity() << endl;
	return 0;
}

 

resize和reserve

resize的作用是改变容器的size

        如果参数n的值小于当前size,则该函数会将size调整为n值,并且删除超出的元素。

        如果参数n的值大于当前size,则会在末尾插入元素至size等于n值。如果我们传了val参数,则后续插入的元素被初始化为val的副本;如果没有传val参数,则会调用其构造函数来初始化元素(实际上,内置类型也有"构造函数",内置类型默认构造初始化的结果一般为0)。另外,如果参数n的值也大于capacity的值,则容器会额外分配空间便于插入元素。

注意:该函数本质是通过插入或删除元素来改变size的值。

 reserve的作用是为容器预留空间(增容)

        如果参数n小于等于当前容量,则不会进行任何操作。

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

注意:该函数对容器内的元素不会有任何影响。

代码示例:

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

int main()
{
	vector<int> v1 = { 1,2,3,4,5 };
	cout << "v1 size:" << v1.size() << " capacity:" << v1.capacity() << endl;

	v1.resize(10);
	cout << "v1 size:" << v1.size() << " capacity:" << v1.capacity() << endl;

	v1.reserve(20);
	cout << "v1 size:" << v1.size() << " capacity:" << v1.capacity() << endl;
	return 0;
}

empty

empty用于判断容器是否为空(即元素个数是否为0)。如果为空,返回true;否则返回false。

该函数不会修改容器的元素内容

三、vector的迭代器接口

vector的迭代器和string使用方法类似,我们都可以通过迭代器接口来获取迭代器,进而访问数据元素。

begin和end

begin返回指向首元素的正向迭代器,而end返回指向末尾元素“后一位”的正向迭代器

代码举例:

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

int main()
{
	vector<int> v1 = { 1,2,3,4,5 };
	for (auto it = v1.begin(); it != v1.end(); it++)
	{
		cout << *it << ' ';
	}
	cout << endl;
	return 0;
}

rbegin和rend

rebegin返回指向末尾元素的反向迭代器,rend返回指向首元素“前一位”的反向迭代器 

代码示例:

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

int main()
{
	vector<int> v1 = { 1,2,3,4,5 };
	for (auto it = v1.rbegin(); it != v1.rend(); it++)
	{
		cout << *it << ' ';
	}
	cout << endl;
	return 0;
}

cbegin、cend、crbegin、crend

这四种迭代器是在前四种迭代器的基础上修改为只能进行读操作,不可修改指向的值。这里不再赘述。

四、vector的元素访问接口

元素访问接口便于我们访问和修改容器内的元素。

operator[ ]

operator[ ]可以让我们像访问数组元素一样访问和修改容器中的元素。它的使用方法与下标引用操作符相同。这里需要注意:可移植程序不应该使用超出范围的参数n调用此函数,因为这会导致未定义的行为

代码举例:

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

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

at

at的作用与operator[ ]相同,该函数需要传入的参数对应数组下标。与operator[ ]不同的是:如果越界访问,at会抛出异常,而operator[ ]会导致未定义行为。

代码示例:

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

int main()
{
	vector<int> v1 = { 1,2,3,4,5 };
	for (size_t i = 0; i < v1.size(); i++)
	{
		cout << v1.at(i) << ' ';
	}
	cout << endl;
	return 0;
}

front和back

front返回容器首元素的引用,而back返回容器末尾元素的引用。我们可以使用这两个函数来访问或修改容器的首尾元素。 

代码示例:

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

int main()
{
	vector<int> v1 = { 1,2,3,4,5 };
	cout << v1.front() << endl;
	cout << v1.back() << endl;
	return 0;
}

五、vector的增删查改

push_back

push_back的功能是尾插一个元素,该元素被初始化为val的副本。当容量不足时会自动扩容。 

pop_back

pop_back用于删除尾部元素

insert

insert用于在指定位置进行插入。这里的位置需要用迭代器进行指定。该函数支持单个元素插入、n个val值插入、迭代器区间插入以及初始化器插入。完成插入操作后,它会返回新插入部分首元素的正向迭代器

使用举例:

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

void print(vector<int>& v)
{
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << ' ';
	}
	cout << endl;
}

int main()
{
	vector<int> v1 = { 1,2,3,4,5 };
	print(v1);

	v1.insert(v1.end(), 10);//元素插入
	print(v1);

	v1.insert(v1.end(), 3, 7);//n个val值插入
	print(v1);

	v1.insert(v1.end(), v1.begin(), v1.end());//迭代器区间插入
	print(v1);

	v1.insert(v1.end(), { 9,9,9,9,9 });//初始化器插入
	print(v1);
	return 0;
}

 

erase

erase的作用是删除指定位置的元素或区间。指定的元素或区间都需要用迭代器表示。函数的返回值是删除部分的后一个位置的正向迭代器。

代码举例:

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

void print(vector<int>& v)
{
	for (int i = 0; i < v.size(); i++)
	{
		cout << v[i] << ' ';
	}
	cout << endl;
}

int main()
{
	vector<int> v1 = { 1,2,3,4,5,6,7,8,9,10 };
	print(v1);

	v1.erase(v1.begin() + 3);//删除元素
	print(v1);

	v1.erase(v1.begin() + 1, v1.begin() + 4);//删除区间
	print(v1);
	return 0;
}

 

swap

swap用于交换两个vector容器的内容。 

当然,与string相同,它也有一个非成员函数版的swap:

clear

clear的作用是将容器中的所有元素清除,并且将size置为0。

find

在vector的成员函数中,我们发现并没有用于查找的函数(find),那么如何进行查找呢?答案是使用STL实现的通用find。该find函数定义在算法库<algorithm>当中,用于容器元素的查找。它接受两个迭代器参数和一个值参数,表示需要查找的区间和值如果找到了,函数会返回指向第一个查找到的元素的迭代器,否则返回尾迭代器

使用举例:

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

int main()
{
	vector<int> v1 = { 1,2,3,4,5,6,7,8,9,10 };
	int n = 0;
	while (cin >> n)
	{
		if (find(v1.begin(), v1.end(), n) != v1.end())
		{
			cout << "找到了" << endl;
		}
		else
		{
			cout << "没找到" << endl;
		}
	}
	return 0;
}

六、vector灵活运用:创建字符串数组

        之前提到,vector本质是一个类模板,我们可以自由设定容器的元素类型。那么,是否可以用vector创建一个字符串数组呢?

代码示例:

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

int main()
{
	vector<string> v;
	v.push_back("hello");
	v.push_back("world");

	for (auto& e : v)
	{
		cout << e << ' ';
	}
	cout << endl;
}

 

在上述代码中,我们传入模板参数“string”,这使得vector容器内的每一个元素都是一个string对象,这样就可以用vector来存储多个字符串了。由于c++自动调用自定义成员构造函数和析构函数的特性,我们也无需担心初始化与空间释放问题。当然我们也可以使用" vector<vector<int>> "来创建一个动态的二维数组,运用方式十分灵活。

总结

        今天我们学习了STL另一个容器--vector的使用。不难发现,它的许多接口名称与string是相同的,这种实现方式也有助于我们学习、使用和理解STL各种各样的容器。之后博主会带大家深入学习vector的底层原理,并尝试模拟实现。如果你觉得博主讲的还不错,就请留下一个小小的赞在走哦,感谢大家的支持❤❤❤

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

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

相关文章

【数据分享】2024年我国省市县三级的生活服务设施数量(46类设施/Excel/Shp格式)

人才市场、售票处、旅行社等生活服务设施的配置情况是一个城市公共基础设施完善程度的重要体现&#xff0c;一个城市生活服务设施种类越丰富&#xff0c;数量越多&#xff0c;通常能表示这个城市的公共服务水平越高&#xff01; 本次我们为大家带来的是我国各省份、各地级市、…

自定义SpringBoot的Start应用场景及常见错误

开发背景 为了将环信(即使通讯)的模块独立出来实现复用&#xff0c;提供给多个模块使用。 实现方式 1.目录结构 2.添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> &l…

gdb和make工具

gdb工具&#xff1a; GDB的主要功能 断点设置&#xff1a;允许开发者在特定的代码行设置断点&#xff0c;当程序执行到该行时会自动暂停&#xff0c;方便开发者进行调试和分析。 变量查看与修改&#xff1a;在程序运行过程中&#xff0c;可以查看和修改变量的值&#xff0c;以…

Ceisum无人机巡检视频投放

公司投标内容有个视频投放的功能动画&#xff0c;原本想实现这么一个效果&#xff1a; 案例效果来自别人的展示作品&#xff0c;Leader一眼就相中了这个效果&#xff0c;可惜别人的终究是别人的&#xff0c;又不会白白给你&#xff0c;终究是要自己动手尝试。 动画方面的展示…

Spring:Bean(创建方式,抽象继承,工厂Bean,生命周期)

1&#xff0c;Bean的创建 1.1&#xff0c;调用构造器创建Bean 调用Bean类的无参构造函数来创造对象&#xff0c;因此要求提供无参构造函数。在这种情况下class元素是必须的&#xff0c;值就是Bean对象的实现类。 如果采用设值注入&#xff0c;Spring容器将使用默认的构造器来创…

ViT面试知识点

文章目录 VITCLIPBlipSAMLSegFast TransformerYOLO系列问题 BatchNorm是对一个batch-size样本内的每个特征做归一化&#xff0c;LayerNorm是对每个样本的所有特征做归一化。 Layer Normalization&#xff08;层归一化&#xff0c;简称LayerNorm&#xff09;是一种在深度学习中…

了解数据库并发产生的问题

在数据库管理系统中&#xff0c;并发控制是一个至关重要的方面。随着多个用户或进程同时访问和修改数据库中的数据&#xff0c;如果没有适当的并发控制机制&#xff0c;就可能导致数据不一致、丢失更新、脏读、不可重复读和幻读等问题。在单用户系统中&#xff0c;数据库操作是…

qt QFontDialog详解

1、概述 QFontDialog 是 Qt 框架中的一个对话框类&#xff0c;用于选择字体。它提供了一个可视化的界面&#xff0c;允许用户选择所需的字体以及相关的属性&#xff0c;如字体样式、大小、粗细等。用户可以通过对话框中的选项进行选择&#xff0c;并实时预览所选字体的效果。Q…

【JavaSE】(2) 方法

一、认识方法 1. 方法的定义 修饰符 返回类型 方法名(形参类型 形参名, ......){......return 返回值; } 示例代码&#xff1a; 2. 方法的作用 增强代码的可复用性。&#xff08;避免重复造轮子&#xff09;增强代码的易管理性。&#xff08;改方法就行&#xff0c;不用到处…

享元模式及其运用场景:结合工厂模式和单例模式优化内存使用

介绍 享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;它通过共享对象来减少内存使用&#xff0c;尤其是对于大量相似对象的场景。享元模式通常与工厂模式和单例模式结合使用&#xff0c;从而有效地控制和复用对象的创建。在享元模式中&am…

【RabbitMQ】03-交换机

1. 交换机 2. Fanout交换机 广播。生产者向exchange发消息 SpringBootTest public class SpringAmqpTest {Autowiredpublic RabbitTemplate rabbitTemplate;Testvoid testSimple() {String exchangName "hmall.fabout";rabbitTemplate.convertAndSend(exchangName…

【赵渝强老师】安装部署Memcached

Memcached是一个高性能的分布式的内存对象缓存系统。通过使用Memcached可以支持高负载的网站系统&#xff0c;以分担数据库的压力。Memcached通过在内存里维护一个统一的巨大的Hash表来存储各种格式的数据&#xff0c;包括图像、视频、文件以及数据库检索的结果等。但是Memcach…

代码要走的路:编程“三部曲”

代码要成为可以运行的程序&#xff0c;总共有3步&#xff1a; 1&#xff0e;编辑&#xff08;edit&#xff09; 这里的编辑不是像出版编辑那样&#xff0c;只把现成的东西修修改改&#xff0c;而是指编写代码。 编写代码是实实在在的原创&#xff0c;不是整理加工&#xff0…

支持向量机相关证明 解的稀疏性

主要涉及拉格朗日乘子法&#xff0c;对偶问题求解

漫途焊机安全生产监管方案,提升安全生产管理水平!

随着智能制造时代的到来&#xff0c;企业安全生产管理的重要性日益凸显。特别是在现代工厂中&#xff0c;焊机的安全生产监管成为了一个不容忽视的重要环节。传统的焊机安全生产监管方式存在诸多不足&#xff0c;如人工巡检频率低、数据延迟、安全隐患发现不及时等问题。因此&a…

【dvwa靶场:XSS系列】XSS (Reflected)低-中-高级别,通关啦

一、低级low 简单拿捏 <script>alert(123)</script>二、中级middle 源码过滤了script但是没有过滤大小写&#xff0c;改成大写S <Script>alert(123)</script>三、高级high 比中级高&#xff0c;过滤了script并且以及大小写&#xff0c;使用其他标…

太速科技-634-基于3U PXIe的VU3P FMC+数据接口板

基于3U PXIe的VU3P FMC数据接口板 一、产品概述 板卡是一款基于 3U PXIE 总线架构的高性能数据预处理FMC 载板&#xff0c;具有 1 个 FMC&#xff08;HPC&#xff09;接口&#xff0c;1 个 X8 GTH 背板互联接口&#xff0c;可以实现 1 路 PCIe x8。板卡主控芯片采用Xilin…

【LLM Agents体验】Dify框架的安装指南

Dify简介&#xff1a; 核心功能‌12 ‌Dify是一款开源的大语言模型(LLM)应用开发平台&#xff0c;融合了后端即服务&#xff08;Backend as a Service, BaaS&#xff09;和LLMOps的理念&#xff0c;使开发者可以快速搭建生产级的生成式AI应用。LLMOps涵盖了大型语言模型的开发、…

推荐一款PowerPoint转Flash工具:iSpring Suite

iSpring Suite是一款PowerPoint转Flash工具&#xff0c;使用iSpring Suite 8可以轻松的将PPT演示文档转换为对Web友好的Flash影片格式。软件界面简洁&#xff0c;使用方便。为什么要转换成flash格式呢?Flash格式的最大特点是体积小巧、易于分发&#xff0c;兼容所有的操作系统…

数据库->视图

目录 一、视图 1.什么是视图 ​编辑 2.创建视图 1.语法 3.使用视图 4.视图的功能 1.屏蔽相关字段 2.对外提供统一访问规范 3.视图和真实表进行表连接查询 5.修改数据 6.注意事项 7.删除视图 1.语法 8.视图的优点 1. 简单性 2. 安全性 3. 逻辑数据独⽴性 4. 重…