【C++】vector详解,模拟实现

news2024/12/26 3:33:25

目录

1. vector的介绍

2. vector的使用

2.1 构造函数

2.2 遍历方式

2.3 reserve与resize

2.4 shrink_to_fit 

2.5 insert,erase,find

3. vector模拟实现

3.1 初始结构

3.2 析构函数 

3.3 获取容量和元素个数

3.4 扩容reserve

3.5 resize改变有效个数并赋值val

3.6 方括号访问operator[]

3.7 迭代器

3.8 insert在pos前面插入

3.9 尾插push_back

3.10 erase删除pos位置的值

3.11 拷贝构造

3.12 赋值重载

3.13 用迭代器区间构造

3.14 用n个val构造


1. vector的介绍

vector是模板实现的。

Vectors are sequence containers representing arrays that can change in size.

 

2. vector的使用

使用上分几大部分:默认成员函数,迭代器,容量相关,访问相关,修改。

2.1 构造函数

void test1()
{
	//无参
	vector<int> v1;

	//有参
	vector<int> v2(10); //val的缺省值是0。
	vector<int> v3(10, 1);

	//迭代器
	vector<int> v4(v3.begin(), v3.end());

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

2.2 遍历方式

1. 下标加[ ],2. 迭代器,3. 范围for。

void test2()
{
	vector<int> v(10, 5);

	//下标+[]
	for (size_t i = 0; i < v.size(); i++)
	{
		cout << v[i] << " ";
	}
	cout << endl;

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

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

2.3 reserve与resize

reserve改变容量。

预先开空间就用reserve,容量改变,有效个数不变。


 

resize改变有效个数。


【区别】


【扩容机制】

vs:1.5倍扩容,g++:2倍扩容

2.4 shrink_to_fit 

缩容:将容量缩到和有效个数一样。

一般是异地缩容。

2.5 insert,erase,find

(1)在pos位置的元素前面插入val。

(2)在pos位置的元素前面插入n个val。

(3)在pos位置的元素前面插入一段迭代器区间。

注意:传入的是迭代器。


找到pos的位置需要借助find,find在算法库里,容器通用。

find传的迭代器区间都是左闭右开,没找到就返回last。


 删除某个位置或一段区间。

 


【结合用法】

void test3()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

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

	//在3前面插入6
	vector<int>::iterator it1 = find(v.begin(), v.end(), 3);
	if (it1 != v.end())
	{
		v.insert(it1, 6);
	}
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	//把6删除
	auto it2 = find(v.begin(), v.end(), 6);
	if (it2 != v.end())
	{
		v.erase(it2);
	}
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

vector官方文档:vector - C++ Reference (cplusplus.com) 

 

3. vector模拟实现

3.1 初始结构

_start指向元素开始位置,_finish指向最后一个元素的下一个位置,_end指向最大容量的下一个位置。

namespace lyh
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;

		//无参构造
		vector()
		{}
		
	private:
		iterator _begin = nullptr;  //元素开始位置。
		iterator _end = nullptr;    //元素末尾的下一个位置。
		iterator _capacity = nullptr;    //最大容量的下一个位置。
	};
}

3.2 析构函数 

释放空间,指针置空。

        ~vector()
		{
			delete[] _begin;
			_begin = nullptr;
			_end = nullptr;
			_capacity = nullptr;
		}

3.3 获取容量和元素个数

利用指针相减。

		size_t size() const
		{
			return _end - _begin;
		}

		size_t capacity() const
		{
			return _capacity - _begin;
		}

3.4 扩容reserve

 n小于容量不用管,n大于容量才扩容。

新开一个大空间,拷贝数据,释放原空间,更新成员变量的指向。

memcpy是浅拷贝,这里用赋值重载才能完成深拷贝,内置类型就浅拷贝,自定义类型就调用自己的赋值重载。

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t sz = size();
				T* tmp = new T[n];
				//原空间有数据才需要拷贝。
				if (_begin)
				{
					for (size_t i = 0; i < sz; i++)
					{
						tmp[i] = _begin[i];
					}
					//释放原空间。
					delete[] _begin;
				}
				//更新成员指向。
				_begin = tmp;
				_end = tmp + sz;
				_capacity = tmp + n;
			}
		}

3.5 resize改变有效个数并赋值val

改变有效个数有三种情况。

小于原先size就缩小。

大于size就交给reserve判断要不要扩容,然后不断尾插直到n。

		void resize(size_t n, const T& val = T())
		{
			if (n <= size())
			{
				_end = _start + n;
			}
			else
			{
				reserve(n);
				while (_end < _begin + n)
				{
					*_end = val;
					++_end;
				}
			}
		}

3.6 方括号访问operator[]

需要断言传入的下标是否合法,返回下标对应的元素的别名。可以提供const版本,可以访问但不能修改。

		T& operator[](size_t pos)
		{
			assert(pos < size());
			return _begin[pos];
		}
		const T& operator[](size_t pos) const
		{
			assert(pos < size());
			return _begin[pos];
		}

3.7 迭代器

begin指向第一个位置,end指向最后一个位置的下一个。可以提供const版本。

		iterator begin()
		{
			return _begin;
		}
		iterator end()
		{
			return _end;
		}
		const_iterator begin() const
		{
			return _begin;
		}
		const_iterator end() const
		{
			return _end;
		}

3.8 insert在pos前面插入

先断言pos在合法范围,再判断是否需要扩容,然后pos位置开始往后挪给pos腾出空间插入。

扩容是异地扩容除了更新原本的成员变量指向还需更新pos的指向,不然pos会变成野指针也就是迭代器失效。

		void insert(iterator pos, const T& val)
		{
			assert(pos >= _begin && pos <= _end);
			
			if (_end == _capacity)
			{
				size_t len = pos - _begin;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				pos = _begin + len;
			}

			iterator key = _end;
			while (key > pos)
			{
				_start[key] = _start[key - 1];
				--key
			}
			*key = val;
			++_end;
		}

3.9 尾插push_back

复用insert

		void push_back(const T& val)
		{
			insert(end(), val);
		}

3.10 erase删除pos位置的值

先断言pos是否合法,然后将pos之后的位置往前移。

erase之后认为迭代器失效,不能访问。

 ​

返回的迭代器指向原本删除元素的下一个元素。

An iterator pointing to the new location of the element that followed the last element erased by the function call.

		iterator erase(iterator pos)
		{
			assert(pos >= _begin && pos < _end);

			iterator key = pos + 1;
			while (key < _end)
			{
				*(key-1) = *key;
				++key;
			}
			--_end;

			return pos;
		}

3.11 拷贝构造

先开一个和v一样大的空间,再把v的元素拷贝过来(遍历尾插)。

		vector(const vector<T>& v)
		{
			reserve(v.capacity());
			for (auto& e : v)
			{
				push_back(e);
			}
		}

3.12 赋值重载

假设v3 = v1,将v1传值拷贝构造给tmp,v3和tmp交换。先拷贝构造给了形参再和形参交换。

		void swap(vector<T>& tmp)
		{
			std::swap(_begin, tmp._begin);
			std::swap(_end, tmp._end);
			std::swap(_capacity, tmp._capacity);
		}
		vector<T>& operator=(vector<T> tmp)
		{
			swap(tmp);
			return *this;
		}

3.13 用迭代器区间构造

当begin不等于end就不断尾插。

		vector(InputIterator begin, InputIterator end)
		{
			while (begin != end)
			{
				push_back(*begin);
				++begin;
			}
		}

3.14 用n个val构造

复用用resize。

		vector(size_t n, const T& val = T())
		{
			resize(n, val);
		}

Vector/Vector · 林宇恒/code-cpp - 码云 - 开源中国 (gitee.com) 

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

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

相关文章

最新简洁大方的自动发卡网站源码/鲸发卡v11.61系统源码/修复版

源码简介&#xff1a; 最新简洁大方的自动发卡网站源码&#xff0c;它就是鲸发卡v11.61系统源码&#xff0c;它是修复版。 说到鲸发卡系统&#xff0c;鲸发卡系统在发卡圈很多人都知道的&#xff0c;它是市面最好发卡系统之一&#xff0c;操作起来简单得很&#xff0c;界面也…

【数据结构】排序算法---快速排序

文章目录 1. 定义2. 算法步骤3. 动图演示4. 性质5. 递归版本代码实现5.1 hoare版本5.2 挖坑法5.3 lomuto前后指针 6. 优化7. 非递归版本代码实现结语 1. 定义 快速排序是由东尼霍尔所发展的一种排序算法。在平均状况下&#xff0c;排序 n 个项目要 O ( n l o g n ) Ο(nlogn) …

在 Windows 上恢复已删除的 PDF 文件的最佳方法

如果您不小心删除了 PDF 文件或由于系统突然崩溃而无法再找到它们&#xff0c;本指南介绍了恢复已删除文件的最佳方法。 帖子中列出的方法简单、有效且可行。我们在列出它们之前对其进行了测试。 什么是 PDF&#xff0c;Adobe 将未保存的 PDF 存储在哪里&#xff1f; 自从 Ad…

数据清洗-缺失值填充-K-NN算法(K-Nearest Neighbors, K-NN算法)

目录 一、安装所需的python包二、采用K-NN算法进行缺失值填充2.1可直接运行代码2.2以某个缺失值数据进行实战2.2.1代码运行过程截屏&#xff1a;2.2.2填充后的数据截屏&#xff1a; 三、K 近邻算法 (K-Nearest Neighbors, KNN) 介绍3.1 K 近邻算法定义3.2 K 近邻算法的基本思想…

Linux 文件与目录操作命令详解

文章目录 前言创建文件1. touch2. vim 文件内容显示3. cat4. more5. less6. head7. tail 文件&#xff08;目录&#xff09;复制、删除和移动8. cp9. rm10. mv 压缩文件与解压缩11. gzip12. zip 和 unzip 创建目录13. mkdir 删除目录14. rmdir 改变工作目录15. cd16. pwd 显示目…

六、二分搜索-算法总结

文章目录 六、二分搜索6.1 简介6.2 典型实例 -- 二分查找6.2 模板6.3 常见题目6.3.1 搜索插入位置6.3.2 搜索二维矩阵6.3.3 寻找旋转排序中数组中的最小值6.3.4 寻找旋转排序数组中的最小值 II6.3.5 搜索旋转排序数组6.3.6 搜索旋转排序数组 II 总结 六、二分搜索 6.1 简介 给…

Java或者前端 实现中文排序(调API的Demo)

目录 前言1. 前端2. Java 前言 前端 Vue 中的中文排序通常使用 JavaScript 提供的 localeCompare 方法来比较中文字符串 Java 后端可以使用 Collator 类来实现中文排序 1. 前端 在 Vue 中&#xff0c;使用 localeCompare 来实现中文字符串的排序&#xff1a; <template&…

Skyeye 云智能制造 v3.14.5 发布,ERP 商城

Skyeye 云智能制造&#xff0c;采用 Springboot winUI 的低代码平台、移动端采用 UNI-APP。包含 30 多个应用模块、50 多种电子流程&#xff0c;CRM、PM、ERP、MES、ADM、EHR、笔记、知识库、项目、门店、商城、财务、多班次考勤、薪资、招聘、云售后、论坛、公告、问卷、报表…

SAM 2: Segment Anything in Images and Videos

SAM2: 在图像和视频中分割任何内容 作者 Nikhila Ravi, Valentin Gabeur, Yuan-Ting Hu, Ronghang Hu 等 (Meta FAIR) 论文&#xff1a;SAM2: Segment Anything in Images and Videos项目代码&#xff1a;GitHub Repository互动演示&#xff1a;Demo 摘要 SAM2 是一个用于处…

基于51单片机的锅炉温度控制系统PID调节proteus仿真

地址&#xff1a; https://pan.baidu.com/s/17oMgAnUBUKKEVnv5hNRQmQ 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectro…

招聘数据分析师,HR会考察候选人哪些方面?

数据分析是必须具备深厚的专业技能底蕴&#xff0c;这是最基本的要求&#xff0c;其中包括对数据分析工具和编程语言的精通&#xff0c;以及对数据库管理的实验操作。 在数据分析师的招聘过程中&#xff0c;必须要注重对方掌握的知识&#xff0c;比如数据挖掘数据可视化等先进…

Qt构建JSON及解析JSON

目录 一.JSON简介 JSON对象 JSON数组 二.Qt中JSON介绍 QJsonvalue Qt中JSON对象 Qt中JSON数组 QJsonDocument 三.Qt构建JSON数组 四.解析JSON数组 一.JSON简介 一般来讲C类和对象在java中是无法直接直接使用的&#xff0c;因为压根就不是一个规则。但是他们在内存中…

详解:Tensorflow、Pytorch、Keras(搭建自己的深度学习网络)

这是一个专门对Tensorflow、Pytorch、Keras三个主流DL框架的一个详解和对比分析 一、何为深度学习框架&#xff1f; 你可以理解为一个工具帮你构建一个深度学习网络&#xff0c;调用里面的各种方法就能自行构建任意层&#xff0c;diy你想要的DNN&#xff0c;而且任意指定学习…

揭秘!当业务方需求模糊,产品经理如何施展‘化雾为金’的神奇策略!

引言 在产品管理的实践中&#xff0c;产品经理经常会遇到业务方无法清晰表达需求的情况。这可能是由于业务方对问题的理解不够深入&#xff0c;或者缺乏将业务需求转化为产品需求的经验。作为资深产品经理&#xff0c;我们需要采取一系列策略来应对这一挑战&#xff0c;确保产…

Solid Converter PDF9.1安装教程

软件介绍 Solid Converter PDF是一套专门将PDF文件转换成word的软件&#xff0c;除了转换成word文件外&#xff0c;还可以转换成RTF以及Word XML文件。除此之外&#xff0c;它还有一个图片撷取功能&#xff0c;可以让我们]将PDF档里的图片撷取出来&#xff0c;以及将PDF档里的…

word文档的读入(8)

如何读取答题卡中的选择题答案&#xff0c;并把所有的信息导入到Excel表格中&#xff5e; 在初始化了字典中的字段并获取了标准答案和学生答案后&#xff0c;现在只需使用if语句将学生答案studentAnswerOne和标准答案value进行比较。选择题一道题2分&#xff0c;答案正确时&…

C++11 右值引用完美转发

前言 上一期介绍了C11的基础新特性&#xff0c;这一期开始我们继续来介绍C11的新特性&#xff01; 目录 前言 一、右值引用和移动语义 1.1左值和左值引用 1.2右值和右值引用 1.3左值引用vs右值引用 1.4右值引用的使用场景和意义 左值引用的使用场景 左值引用的缺陷 …

应用案例|开源 PolarDB-X 在互联网安全场景的应用实践

背景介绍 中盾数科集团始创于2012年&#xff0c;是由网络安全服务而发展起来的科技型、多元化的企业集团。旗下包括网络安全服务、信创一体化服务、箱式液冷、区块链、位置服务、视觉服务等六大板块&#xff0c;业务覆盖湖南、甘肃、贵州等多个省份。 业务挑战 中盾集团基于A…

LabVIEW提高开发效率技巧----模块化设计与代码复用

模块化设计是现代软件开发中不可或缺的理念&#xff0c;在LabVIEW开发中尤为重要。通过将系统功能划分为独立的、可复用的模块&#xff0c;开发者可以显著提升代码的可读性、维护性以及效率。下面将介绍模块化设计的核心概念、如何利用子VI实现代码复用、以及使用模板&#xff…

claude,gpt,通义千问

起因是通义千问对这张图的解释有严重错误&#xff0c;因此想着让claude和gpt回答一下&#xff0c;记录一下。 claude 这张图表显示了中国多个城市的房地产价格指数数据。让我为您解读一下主要信息&#xff1a; 指标解释&#xff1a; "环比": 与上月相比的价格变化&…