STL——vector的使用(快速入门详细)

目录

前言

一、基本知识

二、使用

2.1vector定义

2.2迭代器

2.3空间管理

2.4增删查改

2.4.1尾插尾删

2.4.2插入删除

[2.4.3[ ]、swap、assign](#2.4.3[ ]、swap、assign)

2.4.4find

总结


前言

本篇文章目的是为了快速掌握vector的使用,这里对常用的进行演示助于理解,其它的也会给出。


一、基本知识

1、向量是表示可变大小数组的序列容器。

2、与数组一样,向量使用连续的存储位置来存放其元素,这意味着其元素也可以通过常规指针的偏移量来访问,并且访问效率与数组一样高。但与数组不同的是,向量的大小可以动态改变,其存储空间由容器自动处理。

3、在内部,向量使用动态分配的数组来存储其元素。当向容器中插入新元素时,此数组可能需要重新分配以增大容量,这意味着要分配一个新的数组并将所有元素移动到新数组中。从处理时间来看,这是一项相对昂贵的任务,因此向量不会在每次向容器添加元素时都进行重新分配。

相反,向量容器可能会分配一些额外的存储空间以适应可能的增长,因此容器的实际容量可能大于严格容纳其元素所需的存储空间(即其大小)。库可以实现不同的增长策略来平衡内存使用和重新分配,但在任何情况下,重新分配都应仅在大小的对数增长间隔发生,以便向量末尾插入单个元素的操作能够提供摊还常量时间复杂度(参见 push_back)。

因此,与数组相比,向量会消耗更多的内存,以换取能够高效地管理存储空间并动态增长的能力。

与动态序列容器中的其他类型(双端队列、列表和前向列表)相比,向量在访问其元素方面非常高效(就像数组一样),并且在向其末尾添加或删除元素方面相对高效。对于在末尾以外的位置插入或删除元素的操作,它们的表现不如其他类型,并且其迭代器和引用的稳定性不如列表和前向列表。

二、使用

2.1vector定义

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

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int> AA;//无参初始化
	vector<int> BB(5,1);//初始化5个1
	vector<int> CC(BB);//拷贝构造
    AA = CC;//赋值构造AA
	int data[] = { 1,2,3,4,5 };
	vector<int> DD(data,data+sizeof(data)/sizeof(int));//使用迭代器初始化数据data
	
    vector<int>::iterator it = DD.begin();//迭代器访问数据
	while (it != DD.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	return 0;
}

2.2迭代器

|-----------------|---------------------------------------------------------------------------|
| iterator的使用 | 接口说明 |
| begin + end(重点) | 获取第一个数据位置的iterator/const_iterator, 获取最后一个数据的下一个位置的iterator/const_iterator |
| rbegin + rend | 获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置的reverse_iterator |

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
	int data[] = { 1,2,3,4,5 };
	vector<int> DD(data, data + sizeof(data) / sizeof(int));//使用迭代器初始化数据data
	vector<int>::iterator it = DD.begin();//正向迭代器
	while (it != DD.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
	vector<int>::reverse_iterator il = DD.rbegin();//反向迭代器
	while (il != DD.rend())
	{
		cout << *il << " ";
		++il;
	}
	cout << endl;
	return 0;
}

2.3空间管理

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

reserve(n) 是一个用于预分配容器内存空间 的成员函数,其作用是确保容器的 "容量(capacity)" 至少为 n,但不会改变容器中实际存储的元素数量(size),当调用 reserve(n) 时,若传入的 n(即目标 reserve 值)小于容器当前的容量(current capacity),其行为会因编程语言 / 容器的设计规则不同而有显著差异,核心逻辑可分为 "不操作" 和 "可能收缩容量" 两类,

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
	int data[] = { 1,2,3,4,5 };
	vector<int> DD(data, data + sizeof(data) / sizeof(int));//使用迭代器初始化数据data
	cout << DD.capacity() << endl;//获取DD容量大小
	cout << DD.size() << endl;//获取DD元素个数
	cout << DD.empty() << endl;//判断是否为空
	for (auto e : DD)
	{
		cout << e << " ";
	}
	cout << endl;
	DD.resize(3);//设置当前容量大小为大于等于3,元素数量为3
	DD.resize(6, 1);//设置当前容量大于等于6,元素数量为6,多的部分初始化为1
	cout << DD.capacity() << endl;//获取DD容量大小
	cout << DD.size() << endl;//获取DD元素个数
	for (auto e : DD)
	{
		cout << e << " ";
	}
	cout << endl;
	DD.reserve(2);//设置空间容量为2,此时小于原来容量,根据扩容机制的不同可能会不变或者进行缩减
	cout << DD.capacity() << endl;//获取DD容量大小
	cout << DD.size() << endl;//获取DD元素个数
	for (auto e : DD)
	{
		cout << e << " ";
	}
	cout << endl;
	DD.reserve(10);//设置空间容量为10,根据扩容机制的不容可能会大于等于10
	cout << DD.capacity() << endl;//获取DD容量大小
	cout << DD.size() << endl;//获取DD元素个数
	for (auto e : DD)
	{
		cout << e << " ";
	}

	return 0;
}

2.4增删查改

|-------------------|--------------------------------------------------------------------------------------------------------------------------|
| vector增删查改 | 接口说明 |
| push_back(重点) | 尾插 |
| pop_back (重点) | 尾删 |
| find | 查找。(注意这个是算法模块实现,不是vector的成员接口) |
| insert | 在position之前插入val |
| erase | 删除position位置的数据 |
| swap | 交换两个vector的数据空间 |
| operator[] (重点) | 像数组一样访问 |
| assign | 为向量分配新内容,替换其当前内容,并相应地修改其大小 |

2.4.1尾插尾删

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int> A;
	A.push_back(1);//尾插1
	A.push_back(2);//尾插2
	A.push_back(3);//尾插3
	A.push_back(4);//尾插4
	A.push_back(5);//尾插5
	A.pop_back();//尾删
	A.pop_back();//尾删
	A.pop_back();//尾删
	for (auto e : A)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

2.4.2插入删除

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int> A;
	int arr[] = { 2,3,4 };
	A.insert(A.begin(),0);//头插0
	A.insert(A.begin()+1, 3, 1);//在下标1前插入3个1
	A.insert(A.begin() + 4, arr,arr+3);//在下标4前插入arr
	for (auto e : A)
	{
		cout << e << " ";
	}
	cout << endl;
	A.erase(A.begin());//头删
	A.erase(A.begin(), A.begin() + 3);//删除区间3个元素
	for (auto e : A)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

2.4.3[ ]、swap、assign

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
	int arr[] = { 2,3,4 };
	vector<int> A(arr, arr + 3);
	for (size_t i = 0; i < A.size(); i++)
	{
		cout << A[i] << " ";//[]访问元素,同样可以在这里修改
	}
	swap(A[0],A[2]);
	for (auto e : A)
	{
		cout << e << " ";
	}
	cout << endl;
	A.assign(5, 1);//数据变为5个1
	for (auto e : A)
	{
		cout << e << " ";
	}
	cout << endl;
	A.assign(arr, arr + 3);//数据变为arr
	for (auto e : A)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

2.4.4find

注意:这个函数是在algorithm算法库里。

cpp 复制代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
	int a[] = { 1,2,3,4 };
	vector<int> v(a, a + 4);
	//删除3,但是不知道3在什么地方
	vector<int>::iterator pos = find(v.begin(), v.end(), 3);
	if (pos != v.end())
	{
		v.erase(pos);
	}
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

注意,这里涉及到迭代器失效的问题,例如下面是一个删除所有3的一个代码:

cpp 复制代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
	int a[] = { 1,3,2,3,4,3 };
	vector<int> v(a, a + 6);
	//删除所有的3
	//这里崩溃了,涉及到了迭代器失效的问题,如果每次都重头找的话不涉及迭代器的失效问题,但是效率就有一些低
	vector<int>::iterator pos = find(v.begin(),v.end(),3);
	while (pos != v.end())
	{
		v.erase(pos);
		pos=find(pos+1, v.end(), 3);
	}
	for (auto e : v)
	{
		cout << e << " ";
	}
	return 0;
}

这里删除pos后,空间被释放,而pos也就成了野指针,后续pos+1则找不到。

改正后:

cpp 复制代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
	int a[] = { 1,3,2,3,4,3 };
	vector<int> v(a, a + 6);
	vector<int>::iterator pos = find(v.begin(),v.end(),3);
	while (pos != v.end())
	{
		pos = v.erase(pos);
		pos = find(pos, v.end(), 3);
	}
	for (auto e : v)
	{
		cout << e << " ";
	}
	return 0;
}

erase返回的是下一个元素的迭代器,所以这里就可以这么写。


总结

要注意迭代器失效的问题

相关推荐
汤永红21 分钟前
week4-[二维数组]平面上的点
c++·算法·平面·信睡奥赛
go&Python32 分钟前
检索模型与RAG
开发语言·python·llama
特立独行的猫a1 小时前
C/C++三方库移植到HarmonyOS平台详细教程
c语言·c++·harmonyos·napi·三方库·aki
谱写秋天2 小时前
VSCode+Qt+CMake详细地讲解
c++·ide·vscode·qt·编辑器
毕设源码尹学长2 小时前
计算机毕业设计 java 血液中心服务系统 基于 Java 的血液管理平台Java 开发的血液服务系统
java·开发语言·课程设计
A7bert7772 小时前
【YOLOv5部署至RK3588】模型训练→转换RKNN→开发板部署
c++·人工智能·python·深度学习·yolo·目标检测·机器学习
lumi.2 小时前
2.3零基础玩转uni-app轮播图:从入门到精通 (咸虾米总结)
java·开发语言·前端·vue.js·微信小程序·uni-app·vue
oioihoii3 小时前
现代C++工具链实战:CMake + Conan + vcpkg依赖管理
开发语言·c++
m0_480502643 小时前
Rust 入门 注释和文档之 cargo doc (二十三)
开发语言·后端·rust
黑客影儿3 小时前
使用UE5开发2.5D开放世界战略养成类游戏的硬件配置指南
开发语言·c++·人工智能·游戏·智能手机·ue5·游戏引擎