Vector 模拟实现

前言

本文将会向您介绍如何模拟实现vector

引入

Vector是一种动态数组,也是C++标准库中的容器之一。它提供了一种存储和操作一系列元素的方式,类似于数组,但具有更多的功能和灵活性。

Vector可以存储不同类型的元素,并且可以根据需要动态调整大小。它使用连续的内存块来存储元素,使得元素的访问和遍历效率较高。与普通数组相比,Vector的大小可以动态增长或缩小,而不需要手动编写代码来重新分配内存。

Vector提供了一系列的成员函数和操作符,可以方便地进行元素的插入、删除、访问和修改等操作。它还支持迭代器,可以通过迭代器遍历Vector中的元素。

功能分解

构造

提供了一个默认的构造,和一个n个value的构造

	//构造vector(){}//构造vector(int n, const T& value = T()){reserve(n);for (int i = 0; i < n; i++){push_back(value);}}

拷贝构造

解析:假设用v1拷贝v2,v是v1的别名,将v的内容尾插到v2中
在这里插入图片描述

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

赋值重载

	void swap(vector<T>& v){std::swap(start, v.start);std::swap(finish, v.finish);std::swap(end_of_storage, v.end_of_storage);}vector<T>& operator= (vector<T> v){swap(v);return *this;}

析构

	~vector(){delete[] start;start = finish = end_of_storage = nullptr;}

迭代器

Vector源代码中使用了start、finish、endofstorage三个指针
start指针指向vector中的第一个元素的位置。
finish指针指向vector中最后一个元素的下一个位置。也就是说,finish指针指向vector中当前元素的末尾位置。tips:[start , finish)
endofstorage指针指向vector内部分配的内存空间的末尾位置。这个指针通常用于判断vector是否需要重新分配内存空间。

	iterator begin(){return start;}iterator end(){return finish;}const_iterator begin()	const{return start;}const_iterator end() const{return finish;}//获取大小size_t size() const{return finish - start;}//获取容量size_t capacity() const{return end_of_storage - start;}

尾插:当size与capacity相等时,就需要进行扩容。
以下一个步骤相当于扩容,当尾插需要扩容时,对capacity进行修改
而reserve只是完成扩容的剩下步骤(拷贝空间到新空间,释放旧空间,更新指针指向的位置)

reserve(capacity() == 0 ? 4 : capacity() * 2);

当capacity为0时,赋值4,当capcaity不为0时capacity*2作为参数给reserve

	void push_back(const T& x){if (size() == capacity()){//扩容reserve(capacity() == 0 ? 4 : capacity() * 2);}//插入数据*finish = x;finish ++;//复用//insert(end(), x);}

Reserve

开空间:
场景一:当尾插size与capacity相等时,n接收应需要扩容的大小
开辟一个新空间

T* tmp = new T[n];

如果start不为空,就需要把原来空间里的内容拷贝到新空间里,然后在再释放旧空间

if (start)
{
}
	void reserve(size_t n){size_t sz = size();//开空间if (n > capacity()) {T* tmp = new T[n];//如果start不为空就要拷贝就空间//memcpy(tmp, start, sizeof(T) * sz);if (start){for (int i = 0; i < sz; i++){tmp[i] = start[i];}delete[] start;}//更新start = tmp;finish = start + sz;end_of_storage = start + n;}}

注意:
在更新指针指向的空间时,这里需要提前保存size的大小
不能按如下写法

finish = start + size();

当还没有插入数据时,start应与finish指向的位置相同位于起始位置0处,size( )应为0.但是size()不为0,size = finish - start 旧空间的finish - 新空间的start(tmp)
在这里插入图片描述

Resize

改变大小: n的可能有两种情况,第一是n <= size,直接改变finish指向的位置即可
第二时n > size,需要进行扩容,并且插入Value值

const T& value = T()
	//改变大小void resize(size_t n, const T& value = T()){if (n <= size()){finish = start + n;}else{reserve(n);while(size_t(finish - start) < n){*finish = value;++finish;}}}

Insert

在任意位置pos处插入:
判断有效位置、判断扩容、挪动数据、插入数据
以上步骤的逻辑较为简单不再讲解
注意:
必须要记录pos的相对位置,再对pos进行更新
否则:pos指向要插入的位置,如果扩容后,会将旧空间释放掉,其中包括pos指向的位置,这样一来pos就变成野指针,解引用插入数据的时候就会有问题

	size_t len = pos - start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = start + len;

在这里插入图片描述

	iterator insert(iterator pos, const T& x){//判断有效位置assert(pos >= start);assert(pos <= finish);//判断扩容if (size() == capacity()){//pos失效size_t len = pos - start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = start + len;}//挪动数据T* end = finish - 1;while (end >= pos){*(end + 1) = *end;end--;}*pos = x;finish++;return start;}

另外当我们进行以下测试的时候会出现以下错误
在这里插入图片描述
原因是:
当我们向一个vector中插入元素时,pos是it的拷贝,虽然我们在insert中对pos进行修正,但是pos的修改并不会影响到it迭代器,这种情况下,原有的迭代器指向的内存地址已经不再有效,因此不能再使用。

void test3()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it = v.begin() + 2;v.insert(it, 30);for (auto e : v){cout << e << " ";}cout << endl;v.insert(it, 20);for (auto e : v){cout << e << " ";}
}

Erase

删除:判断有效位置、覆盖数据,最后 - -finish
以上步骤较为简单,就不在这里进行讲解

	iterator erase(iterator pos){//判断有效位置assert(pos >= start);assert(pos < finish);iterator end = pos + 1;while (end < finish){*(end - 1) = *end;  end++;}finish--;return start;}

注意:
当我们测试以下数据并且想erase掉偶数
我们像以下写法使用迭代器还会导致像insert时迭代器失效一样的问题吗
答案是:会的

	while (it != v3.end()){if (*it % 2 == 0){v3.erase(it);}it++;}

测试数据:1 2 2 3 4 5
在这里插入图片描述
我们可以观察到,此时并没有erase掉偶数
原因是 it 指向第一个2的位置,当我们erase移动覆盖第一个2时,此时 第二个2就跑到了it指向的位置,然后再++it,本来应对第二个2进行判断的时候,却直接跳过了
在这里插入图片描述
测试数据:1,2,3,4,5,6
在这里插入图片描述
VS有个特点:erase后不让再使用迭代器,进行了强制检查
当我们erase最后一个偶数时,finish–,然后it++,这会导致it != v3.end()直接失效
在这里插入图片描述
C++库也给出了解决方案
返回被删除数据的下一个位置,我们只需要接收这个位置即可
在这里插入图片描述

void test_vector3()
{vector<int> v3;v3.push_back(1);v3.push_back(2);v3.push_back(2);v3.push_back(3);v3.push_back(4);v3.push_back(5);v3.push_back(6);for (auto e : v3){cout << e << " ";}cout << endl;Fan::vector<int>::iterator it = v3.begin();while (it != v3.end()){if (*it % 2 == 0){it = v3.erase(it);}else{it++;}}for (auto e : v3){cout << e << " ";}
}

测试用例

//void test_vector1()
//{
//	vector<int> v1;
//	v1.push_back(1);
//	v1.push_back(2);
//	v1.push_back(3);
//	v1.push_back(4);
//	v1.push_back(5);
//	v1.insert(v1.begin() + 3, 1);
//	v1.insert(v1.begin(), 0);
//	v1.insert(v1.end(), 1);
//	Fan::vector<int>::iterator it = v1.begin();
//	while (it != v1.end())
//	{
//		cout <<" "<< * it;
//		++it;
//	}
//}//void test_vector2()
//{
//	vector<int> v2;
//	v2.push_back(1);
//	v2.push_back(2);
//	v2.push_back(3);
//	v2.push_back(4);
//	v2.push_back(5);
//	v2.push_back(6);
//	v2.push_back(7);
//	for (auto e : v2)
//	{
//		cout << e << " ";
//	}
//	cout << endl;
//	v2.erase(v2.begin() + 1);
//	v2.erase(v2.begin() + 1);
//	for (auto e : v2)
//	{
//		cout << e << " ";
//	}
//}
//void test_vector3()
//{
//	vector<int> v3;
//	v3.push_back(1);
//	v3.push_back(2);
//	v3.push_back(2);
//	v3.push_back(3);
//	v3.push_back(4);
//	v3.push_back(5);
//	v3.push_back(6);
//	for (auto e : v3)
//	{
//		cout << e << " ";
//	}
//	cout << endl;
//	Fan::vector<int>::iterator it = v3.begin();
//	while (it != v3.end())
//	{
//		if (*it % 2 == 0)
//		{
//			it = v3.erase(it);
//		}
//		else
//		{
//			it++;
//		}
//	}
//	for (auto e : v3)
//	{
//		cout << e << " ";
//	}
//}
//void test_vector4()
//{
//	vector<int> v4;
//	v4.push_back(1);
//	v4.push_back(2);
//	v4.push_back(2);
//	v4.push_back(3);
//	v4.push_back(4);
//	v4.push_back(5);
//	v4.push_back(6);
//	for (auto e : v4)
//	{
//		cout << e << " ";
//	}
//	v4.pop_back();
//	cout << endl;
//	for (auto e : v4)
//	{
//		cout << e << " ";
//	}
//	cout << endl;
//	cout << v4[1];
//}
//void test_vector5()
//{
//	vector<int> v5;
//	v5.push_back(1);
//	v5.push_back(2);
//	v5.push_back(2);
//	v5.push_back(3);
//	v5.push_back(4);
//	vector<int> v6;
//	v6 = v5;
//	for (auto e : v6)
//	{
//		cout << e << " ";
//	}
//}
//void test_vector6()
//{
//	vector<string> v6;
//	v6.push_back("1111111111111111111");
//	v6.push_back("1111111111111111111");
//	v6.push_back("1111111111111111111");
//	v6.push_back("1111111111111111111");
//	v6.push_back("1111111111111111111");
//	v6.push_back("1111111111111111111");
//	v6.push_back("1111111111111111111");
//	v6.push_back("1111111111111111111");
//	v6.push_back("1111111111111111111");
//	v6.push_back("1111111111111111111");
//	for (auto e : v6)
//	{
//		cout << e << " ";
//	}
//}
//void test_vector7()
//{
//	vector<int*> v1;
//	v1.resize(10);
//	vector<string> v2;
//	v2.resize(10, "xxx");
//	for (auto e : v1)
//	{
//		cout << e << " ";
//	}
//	cout << endl;
//	for (auto e : v2)
//	{
//		cout << e << " ";
//	}
//}
//void test_vector8()
//{
//	vector<string> v1;
//	v1.resize(10, "xxx");
//	vector<string> v2(v1);
//	for (auto e : v2)
//	{
//		cout << e << " ";
//	}
//	cout << endl;
//	vector<string> v3(v2.begin(), v2.end());
//	for (auto e : v3)
//	{
//		cout << e << " ";
//	}
//}
int main()
{//test_vector1();//test_vector2();//test_vector3();//test_vector4();//test_vector5();//test_vector6();//test_vector7();//test_vector8();return 0;
}

小结

关于本文Vector代码已经上传到gitee了,如果本文存在遗漏或错误的的地方,还请您能够指出。

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

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

相关文章

【ChatGPT原理与实战】4个维度讲透ChatGPT技术原理,揭开ChatGPT神秘技术黑盒!

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;陈童学哦&#xff0c;目前学习C/C、算法、Python、Java等方向&#xff0c;一个正在慢慢前行的普通人。 &#x1f3c0;系列专栏&#xff1a;陈童学的日记 &#x1f4a1;其他专栏&#xff1a;CSTL&…

HarmonyOS开发:那些开发中常见的问题汇总(一)

前言 本来这篇文章需要讲述静态共享包如何实现远程依赖和上传以及关于静态共享包私服的搭建&#xff0c;非常遗憾的告诉大家&#xff0c;由于组织管理申请迟迟未通过&#xff0c;和部分文档官方权限暂未开放&#xff0c;关于这方面的讲解需要延后了&#xff0c;大概需要等到202…

哈工大校园网显示IP地址错误连接不上

您当前获取到的IP地址有误&#xff0c;请重新开关无线获取IP地址(注:电脑端还可以通过cmd窗口&#xff0c;输入ipconfig /release、ipconfig /renew命令)。如未解决此问题请联系网络安全和信息化办公室处理。 当校园网登录时会出现如上情况&#xff0c;并且当你按照他的方法尝试…

数据结构——图(图的存储及基本操作)

文章目录 前言一、邻接矩阵法&#xff08;顺序存储&#xff09;1.无向图存储邻接矩阵算法2.有向图存储邻接矩阵算法 二、邻接表法(图的链式存储结构)总结 前言 邻接矩阵法(图的顺序存储结构) 1.1 无向图邻接矩阵算法 1.2 有向图邻接矩阵算法邻接表法(图的一种链式存储结构) 一…

56、springboot ------ RESTful服务及RESTful接口设计

★ RESTful服务 RESTful服务是“前后端分离”架构中的主要功能&#xff1a; 后端应用对外暴露RESTful服务&#xff0c;前端应用则通过RESTful服务与后端应用交互。后端应用 RESTful接口 <------------------> 前端★ 基于JSON的RESTful服务 使用RestController注解…

vue项目部署,出现两个ip的原因

我宁愿靠自己的力量打开我的前途,而不愿求有力者的垂青。——雨果 tags: 篇首语&#xff1a;本文由小常识网(cha138.com)小编为大家整理&#xff0c;主要介绍了vue项目部署&#xff0c;出现两个ip的原因相关的知识&#xff0c;希望对你有一定的参考价值。 参考技术A 在部署v…

建站系列(五)--- 前端开发语言之HTML、CSS、JavaScript

目录 相关系列文章前言一、前端开发与后端开发二、前端语言简介&#xff08;一&#xff09;、HTML&#xff08;二&#xff09;、CSS&#xff08;三&#xff09;、JavaScript 三、学习指导&#xff08;一&#xff09;、开发环境&#xff08;二&#xff09;、第一个Hello&#xf…

央媒发稿不能改?媒体发布新闻稿有哪些注意点

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 “央媒发稿不能改”是媒体行业和新闻传播领域的普遍理解。央媒&#xff0c;即中央主要媒体&#xff0c;是权威性的新闻源&#xff0c;当这些媒体发布新闻稿或报道时&#xff0c;其他省、…

Pdf文件签名检查

如何检查pdf的签名 首先这里有一个已经签名的pdf文件&#xff0c;通过pdf软件可以看到文件的数字签名。 下面就是如何代码检查这里pdf文件的签名 1.引入依赖 <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId&g…

时序预测 | MATLAB实现ARMA自回归移动平均模型时间序列预测

时序预测 | MATLAB实现ARMA自回归移动平均模型时间序列预测 目录 时序预测 | MATLAB实现ARMA自回归移动平均模型时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 MATLAB实现ARMA时间序列预测&#xff08;完整源码和数据&#xff09; 本程序基于MATLAB的armax函…

应用在电子体温计中的国产温度传感芯片

电子体温计由温度传感芯片&#xff0c;液晶显示器&#xff0c;纽扣电池&#xff0c;专用集成电路及其他电子元器件组成。能快速准确地测量人体体温&#xff0c;与传统的水银玻璃体温计相比&#xff0c;具有读数方便&#xff0c;测量时间短&#xff0c;测量精度高&#xff0c;能…

gma 2.0.1 (2023.09.15) 更新日志

安装 gma 2.0.1 pip install gma2.0.1修复 1、【栅格处理-栅格分解】   修复了由于关联模块调整导致类方法失效引起的函数功能异常的问题。 2、【栅格处理-栅格更新相关】   修复了自身数据更新相关的函数&#xff08;例如 添加颜色映射表 等&#xff09;格式检查不通过的…

【机器学习习题】估计一个模型在未见过的数据上的性能

您提到的不等式是统计学中的泛化误差界&#xff08;generalization error bound&#xff09;&#xff0c;它用于估计一个模型在未见过的数据上的性能。这个不等式是由Hoeffding不等式和Union Bound组合而成的。在这个不等式中&#xff0c;我们有以下符号&#xff1a; - P[|E_i…

什么是 Microsoft Office 365? Excel on Cloud 的好处

什么是Office 365 Office 365 是 Microsoft 的一套程序&#xff0c;可以在本地运行&#xff0c;也可以同步到云存储。 可以从访问程序。 借助 Office 365&#xff0c;您可以在任何地方进行工作&#xff0c;并与世界各地的同事共享工作文档。 Office 365 支持的设备&#xff1a…

SpringBoot+若依+图片导出

前言 本文基于若依框架&#xff0c;实现excel中图片导出功能。 自定义导出Excel数据注解 public enum ColumnType{NUMERIC(0), STRING(1), IMAGE(2);private final int value;ColumnType(int value){this.value value;}public int value(){return this.value;}} 工具类中设置…

初识 Linux 文件系统

初识 Linux 文件系统 如果是刚接触 Linux 系统&#xff0c;可能就很难搞清楚 Linux 如何引用文件和目录。对于对已经习惯 使用 Windows 操作系统的人来说&#xff0c;难度更大。所以要想学习 Linux 系统&#xff0c;就必须先了解 Linux 文件系统 文章目录 初识 Linux 文件系统…

【PHP图片托管】CFimagehost搭建私人图床 - 无需数据库支持

文章目录 1.前言2. CFImagehost网站搭建2.1 CFImagehost下载和安装2.2 CFImagehost网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar临时数据隧道3.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 4.公网访问测…

华为云云耀云服务器L实例评测|部署前后端分离项目

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 学习测评 ✨特色专栏&#xff1a; MyS…

澳洲硕士申请QA

Q&A 申请一般问题 澳洲申请时间 澳洲分2月跟7月开学&#xff0c;不分rolling。随时申请&#xff0c;截止日期前申请就行&#xff0c;&#xff08;具体时间官网有写&#xff09; 研究生学位时长 它整体的要求一般就是如果说你要申请的这个专业是本专业&#xff0c;那他…

基于spring boot+ vue开发的位置数据展现和分析平台源码 UWB源码

spring boot vue位置数据展现和分析平台源码 UWB室内外高精度定位系统源码 智慧工厂是现代工厂信息化发展的新阶段&#xff0c;基于UWB定位技术&#xff0c;融合位置物联网、GIS可视化等技术&#xff0c;实现对人员、物资精确管理。在重点区域设置电子围栏&#xff0c;无权限…