手撕vector容器

news2024/12/28 3:49:54

一、vector容器的介绍

vector是表示可变大小数组的序列容器。就像数组一样,vector也采用的连续存储空间来存储元素,但是又不像数组,它的大小是可以动态改变的,而且它的大小会被容器自动处理。

总结:vector是一个动态数组,能高效的随机下标访问。
 

二、主要接口

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

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

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

vector增删查改接口说明
push_back(重点)尾插
pop_back (重点)尾删
find查找。(注意这个是算法模块实现,不是vector的成员接口)
insert在position之前插入val
erase删除position位置的数据
swap交换两个vector的数据空间
operator[] (重点)像数组一样访问

三、模拟实现

1.vector 的对象

iterator _start :                指向第一个元素的迭代器

iterator _finish:                  指向最后一个元素下一个位置的迭代器

iterator _endOfStorage :指向动态空间最后一个位置的迭代器

namespace N
{
	template<class T>
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
	private:
		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _endOfStorage = nullptr;
	};
}

模板命名T vector迭代器的本质是指针  

【C++11】关于成员对象给缺省,在构造函数调用初始化列表的时候,会选择用上缺省值

 2.迭代器成员函数begin()和end()

begin():返回指向容器的起始位置的迭代器(非const)

end():返回指向容器的最后位置的下一个位置迭代器(非const)

cbegin():返回指向容器的起始位置的常属性迭代器(const)

cend():返回指向容器的最后位置的下一个位置常属性迭代器(const)

iterator begin(){
	return _start;
}
		
iterator end(){
    return _finish;
}

const_iterator cbegin()const {
	return _start;
}
		
const_iterator cend() const
{
	return _finish;
}

区别:

非const的版本函数返回的迭代器可以用来访问,修改元素

而const版本只能用来访问元素,不准修改

3.容量空间

1)size():返回数据个数

        元素首位迭代器的相减返回个数  (前开后闭返回区间个数)

2)capacity()

        元素容量与头元素迭代器的相减

size_t size() const
{
	return _finish - _start;
}

size_t capacity() const
{
	return _endOfStorage - _start;
}

3)reserve(size_t  n) :改变vector的capacity

如果vector 的capacity大于n ,不进行操作

n>=capacity,扩容,拷贝,释放原空间

同时更新_start    _finish     _endofstorage

void reserve(size_t n)
{
	if (n <= capacity())
	{
		return;
	}
	T* tmp = new T[n];
	size_t sz = size();
	if (_start)
	{
		for (size_t i = 0; i < sz; i++)
		{
			tmp[i] = _start[i];
		}
		delete[]_start;
	}
	_start = tmp;
	_finish = _start + sz;
	_endOfStorage = _start+n;
}

4)resize :改变vector的size

n<size() 改变_finishi

n>=size() reserve空间,size后面的数依次赋值

void resize(size_t n, const T& value = T())
{
	if (n <= size())
	{
		_finish = _start + n;
		return;
	}
	reserve(n);
	while (_finish < n + _start)
	{
		*_finish = value;
		++_finish;
	}
}

关于默认参数 :

匿名对象T()生命周期只有这一行

const修饰匿名对象 延长生命周期 value销毁时匿名对象才销毁

4.vector增删查改

1)push_back():尾插

检查容量,不够就reserve扩容  _finish位置插入数据 ++_finish

void push_back(const T& x)
{
	if (_finish == _endOfStorage)//扩容
	{
		reserve(capacity() == 0 ? 4 : capacity() * 2);
	}

	*_finish = x;
	++_finish;
}

2)pop_back():尾删

--_finish

void pop_back()
{
	_finish--;
}

3)insert(): pos位置之前插入val

检查pos合法

检查是否扩容,注意保存pos的位置,(求出pos-_start)

从最后一个数据往前挪动数据,插入val

更新_finish

iterator insert(iterator pos, const T& x)
{
	assert(pos>=_start);
	assert(pos <= _finish);
	int len = pos - _start;
	if (_finish == _endOfStorage)
	{
		reserve(capacity() == 0 ? 4 : capacity() * 2);
	}
	pos = _start + len;
	//移动数据
	iterator end = _finish-1;
	while (end >= pos)
	{
		*(end + 1) = *end;
		--end;
	}
	*pos = x;
	++_finish;
	return pos;
}

关于迭代器失效:

如果扩容后,原来的空间会被释放掉,那么pos会变成野指针,如果继续使用迭代器,会使用一块已经释放的空间,导致程序可能崩溃。

会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、assign、push_back等
 

4)earse():删除pos的值

检查pos的合法 _start<=pos<=_finish

从前往后挪数据

更新_finish

iterator erase(iterator pos)
{
	assert(pos >= _start);
	assert(pos <= _finish);

	iterator cur = pos+1;
	while (cur != _finish)
	{
		*(cur - 1) = *cur;
		++cur;
	}
	--_finish;
	return pos;
}

涉及迭代器失效问题:

当earse最后一个位置时,迭代器失效,vs上认为使用earse后,不管删除哪个位置迭代器都失效

5)swap :交换俩个vector的数据空间

如果发生赋值,会极大降低效率,因此在vector容器的交换,交换各自的迭代器对象

void swap(vector<T>& v)
{
	::swap(_start, v._start);
	::swap(_finish , v._finish);
	::swap(_endOfStorage, v._endOfStorage);
}

6)operator [ ] :下标访问修改

返回指定空间的引用

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

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

关于const版本和非const版本:
const只读不可改,非const版本可读可改

5.(constructor)构造函数声明

1)无参构造函数:

        不用写具体内容,因为在C++11支持成员变量给缺省,会自动进入初始化列表

2)vector(size_type n, const value_type& val = value_type()) N个value构造

        先开空间,附用reverse函数,尾插

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

3)vector(InputIterator first, InputIterator last):迭代器区间构造

定义迭代器模板,依次尾插

vector(InputIterator first, InputIterator last)
{
	while (first != last)
	{
		push_back(*first);
		++first;
	}
}

4)vector (const vector &x):拷贝构造

开空间,尾插

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

5)operator =:赋值

拷贝构造临时空间,交换

vector<T>& operator= (vector<T> v)
{
	swap(v);
	return *this;
}

6)析构函数

释放空间

总结:

源代码:

STL/vector.h · L_may/C++Study - 码云 - 开源中国 (gitee.com)

本文模拟实现vector容器,在insert和erase中涉及迭代器失效的问题,要多加注意。

作者能力有限,希望对大家有所帮助。
 

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

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

相关文章

OpenAI Function calling

开篇 原文出处 最近 OpenAI 在 6 月 13 号发布了新 feature&#xff0c;主要针对模型进行了优化&#xff0c;提供了 function calling 的功能&#xff0c;该 feature 对于很多集成 OpenAI 的应用来说绝对是一个“神器”。 Prompt 的演进 如果初看 OpenAI 官网对function ca…

计算机网络-物理层(三)编码与调制

计算机网络-物理层&#xff08;三&#xff09;编码与调制 在计算机网络中&#xff0c;计算机需要处理和传输用户的文字、图片、音频和视频&#xff0c;它们可以统称为消息 数据是运输信息的实体&#xff0c;计算机只能处理二进制数据&#xff0c;也就是比特0和比特1。计算机中…

不含数字的webshell绕过

异或操作原理 1.首先我们得了解一下异或操作的原理 在php中&#xff0c;异或操作是两个二进制数相同时&#xff0c;异或(相同)为0&#xff0c;不同为1 举个例子 A的ASCII值是65&#xff0c;对应的二进制值是0100 0001 的ASCII值是96&#xff0c;对应的二进制值是 0110 000…

CSS加载失败的6个原因

有很多刚刚接触 CSS 的新手有时会遇到 CSS 加载失败这个问题&#xff0c;但测试时&#xff0c;网页上没有显示该样式的问题&#xff0c;这就说明 CSS 加载失败了。出现这种状况一般是因为的 CSS 路径书写错&#xff0c;或者是在浏览器中禁止掉了 CSS 的加载&#xff0c;可以重新…

Linux/Ubuntu 的日常更新,如何操作?

我安装的是Ubuntu 20.04.6 LTS的Windows上Linux子系统版本&#xff0c;启动完成后显示&#xff1a; Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.15.90.4-microsoft-standard-WSL2 x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.c…

使用mysql:5.6和owncloud镜像构建个人网盘

一、拉取镜像 使用docker拉取mysql:5.6和owncloud的镜像 [rootexam ~]# docker pull mysql:5.6 [rootexam ~]# docker pull owncloud 运行镜像生成容器实例 [rootexam ~]# docker run -d --name mydb1 --env MYSQL_ROOT_PASSWORD123456 mysql:5.6 a184c65b73ff993cc5cf86f…

保姆级教程:从0到1搭建Stable Diffusion XL完整工作流进行AI绘画 | 【人人都是算法专家】

Rocky Ding 公众号&#xff1a;WeThinkIn 写在前面 【人人都是算法专家】栏目专注于分享Rocky在AI行业中对业务/竞赛/研究/产品维度的思考与感悟。欢迎大家一起交流学习&#x1f4aa; 大家好&#xff0c;我是Rocky。 之前Rocky详细介绍了Stable Diffusion&#xff08;SD&#…

Scratch 之 RPG 引擎制作教程(1) / 地图行走

大家好&#xff0c;又和大家见面了&#xff0c;那么我们这期讲的就是RPG游戏的地图以及人物的行走。 我发现大家并不是很懂RPG游戏引擎&#xff0c;也就是说这种引擎对于技术的要求还是比较高的。为了让更多人直接上手制作RPG游戏&#xff0c;我打算开启这一系列教程。 这个教程…

又一个 Python 图形界面库,简单好用

迷途小书童的Note 读完需要 10分钟 速读仅需 4 分钟 1 环境 python 3.9.16nicegui 1.3.9 2 前言 在现代计算机应用程序开发中&#xff0c;图形用户界面&#xff08;GUI&#xff09;是用户与程序交互的重要组成部分。然而&#xff0c;GUI 开发往往需要大量的代码和复杂的布局&am…

损失函数——感知损失

感知损失&#xff08;Perceptual Loss&#xff09;是一种基于深度学习的图像风格迁移方法中常用的损失函数。与传统的均方误差损失函数&#xff08;Mean Square Error&#xff0c;MSE&#xff09;相比&#xff0c;感知损失更注重图像的感知质量&#xff0c;更符合人眼对图像质量…

webshell实践复现

目录 一.Nginx负载均衡&#xff08;反向代理及负载均衡配置以省略&#xff09; 1.环境搭建 2.复现 二.webshell实践 1&#xff1a;异或操作绕过 2&#xff1a;取反绕过 3&#xff1a;php语法绕过 一.Nginx负载均衡&#xff08;反向代理及负载均衡配置以省略&#xff09; 注…

EndNote(四)【文献引文格式、同步、智能分组、引文报告、文献笔记导出】

参考文献格式&#xff1a;&#xff08;官网引文格式下载文章引文格式更新-word&#xff09; 官网引文格式下载 网址&#xff1a;Downloads | EndNote 点击output styles&#xff1a; 下下来之后&#xff0c;放在这个路径下&#xff1a; 双击看一下&#xff1a; ok. 比如我们要…

Java面试题(1) 为什么重写 equals() 就一定要重写 hashCode() 方法?

目录 一、问题分析1.equals() 的实现2.equals() 和 hashCode() 的关系3.存在的问题 二、完整回答 一、问题分析 1.equals() 的实现 关于这个问题&#xff0c;首先需要深入了解一下 equals() 这个方法。 String 类 equals() 源码如下&#xff1a; public boolean equals(Obj…

Linux —— 进程间通信(System V)

目录 一&#xff0c;共享内存 申请共享内存 shmget 控制共享内存 shmctl 关联共享内存 shmat / 去联共享内存 shmdt 二&#xff0c;消息队列 创建或打开消息队列 msgget 发送消息 msgsnd / 接收消息 msgrcv 控制消息 msgctl 三&#xff0c;信号量 创建或打开信号量 s…

java八股文面试[java基础]——面相对象特点

三大特点&#xff1a; 封装 继承 多态 面试题&#xff1a;java如何实现多继承&#xff08;除了使用接口之外&#xff09; 实现多继承有三个方法&#xff1a; 多层继承内部类接口 知识来源&#xff1a; 【基础】面向对象_哔哩哔哩_bilibili 【2023年面试】Java面向对象有哪些…

Vue--BM记事本

效果如下&#xff1a; 用到了如下的技术&#xff1a; 1.列表渲染&#xff1a;v-for key的设置 2.删除功能&#xff1a;v-on调用参数 fliter过滤 覆盖修改原数组 3.添加功能&#xff1a;v-model绑定&#xff0c;unshift修改原数组添加 html文件如下&#xff1a; <!DOCTYPE …

1.进程控制

1.进程概念 进程是管理事务的基本单元 2.并发并行 并行(parallel)&#xff1a;指在同一时刻&#xff0c;有多条指令在多个处理器上同时执行。并发(concurrency)&#xff1a;指在同一时刻只能有一条指令执行&#xff0c;但多个进程指令被快速的轮换执行&#xff0c;使得在宏观上…

7-5 特殊a串数列求和

分数 20 全屏浏览题目 切换布局 作者 颜晖 单位 浙大城市学院 给定两个均不超过9的正整数a和n&#xff0c;要求编写程序求aaaaaa⋯aa⋯a&#xff08;n个a&#xff09;之和。 输入格式&#xff1a; 输入在一行中给出不超过9的正整数a和n。 输出格式&#xff1a; 在一行中…

回归预测 | MATLAB实现NGO-SVM北方苍鹰算法优化支持向量机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现NGO-SVM北方苍鹰算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现NGO-SVM北方苍鹰算法优化支持向量机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基…

华为网络篇 多区域OSPF-32

难度2复杂度2 目录 一、实验原理 二、实验拓扑 三、实验步骤 四、实验过程 总结 一、实验原理 OSPF是一种具有区域概念的路由协议&#xff0c;为什么需要分区域&#xff1f;像RIP那样都在一个区域配置也不多这样简单点不是更好吗&#xff1f;OSPF它是一种功能十分强大的IG…