刷题常见vector类模板内部实现 看完思路清晰

本文详细解析了C++中vector类模板的构造原理,包括无参、指定长度和迭代器初始化的构造函数,以及尾插、尾删、任意位置插入和删除的内部机制。重点讲解了resize操作和迭代器实现,展示了vector如何自适应存储不同类型的数据并保持高效性能。
摘要由CSDN通过智能技术生成

vector类模板内部实现

无论是在newcode刷题 还是在leetcode刷题  如果采用c++编译环境,功能函数的参数还是返回值均采用vector来进行存储数据

为什么用vector来存储?

究其原因,vector类似于一个数组,通过连续的存储空间来存放数据,对此,访问数据十分方便,但在实现插入删除时却会消耗更多的时间和空间

与其同时,vector底层实现是基于类模板实现,所以,可以存储的数据类型可以自定义  包括int  float  string char  甚至自定义的类,结构体均可,这也是底层类模板实现的好处

下面具体看一下其内部如何实现

 

  • 构造函数(包括无参构造,不同参数类型重载构造函数)

vector():_start(nullptr)
		,_finish(nullptr)
		,_endofstorage(nullptr)
	{

	}
	vector(size_t n, const T& val = T())
		:_start(new T[n])
		,_finish(_start+n)
		,_endofstorage(_start+n)
	{
		for (size_t i = 0; i < n; i++)
		{
			_start[i] = val;
		}
	}

	template <class it>
	vector(it first, it last)
		:_start(nullptr)
		, _finish(nullptr)
		, _endofstorage(nullptr)
	{
		while (first != last)
		{
			push_back(*first);
			first++;
		}
	}

第一个构造函数为无参构造类型,不传入任何参数,通过初始化列表对私有成员进行初始化,由于成员变量均为迭代器(实质为地址,功能类似于指针),初始化为空指针

其中私有成员包括如下:

private:
	iterator _start;
	iterator _finish;
	iterator _endofstorage;//空间的结尾

第二个构造函数,第一个参数为容器长度n,第二个参数为带默认参数的模板类型的值,根据给的长度n,列表初始化通过new开辟n大小的内存空间

第三个构造函数 传入的两个参数为定义为模板类型的迭代器,通过迭代器依次赋值操作

  • 尾插/尾删


	void reverse(size_t n)
	{
		if (n > capacity())
		{
			//保存有效元素个数
			size_t sz = size();
			//申请空间
			T* tmp = new T[n];
			//拷贝原有空间
			if (_start)
			{
				memcpy(tmp, _start, sizeof(T)*size());
				delete[]_start;
			}
			//更新
			_start = tmp;
			//_finish=_start+size();//由于start更新 导致size()出问题  finish丢失
			_finish = _start + sz;
			_endofstorage = _start + n;
		}
	}

	void push_back(const T& val)
	{
		//检查容量
		if(_finish==_endofstorage)
		{
			size_t newcap = _endofstorage == nullptr ? 1 : 2 * capacity();
			reverse(newcap);
		}
		//尾插
		*_finish = val;
		_finish++;
	}

	void pop_back()
	{
		_finish--;
	}

由于vector在实现插入数据时,通过动态开辟空间进行扩容,保证有足够的空间进行插入,所以在插入前第一步要做的就是检查容量

扩容过程无论哪一个模板,基本一致:

  • 申请新空间
  • 拷贝原有数据到新空间
  • 释放原有空间
  • 更新(由于空间拷贝发生变化,成员指针的指向需要更新)

由于有指向尾部元素下一位置的_finish指针存在,尾插及尾删操作需要注意对尾部指针的操作

测试结果如下:

  • 任意位置前插入

void insert(iterator pos, const T& val)
	{
		//检查位置
		assert( pos<=end()&&pos>=begin());
		//检查容量
		if (_finish == _endofstorage)
		{
			//记录偏移量
			size_t offset = pos - _start;
			size_t newcap = _endofstorage == nullptr ? 1 : 2 * capacity();
			reverse(newcap);//增容空间拷贝导致迭代器失效 pos位置丢失
			pos = _start + offset;//增容之后 更新pos位置
		}
		//移动元素
		iterator it = end();
		while (it>pos)
		{
			*it = *(it - 1);
			it--;
		}
		
		*pos = val;
		//更新
		_finish++;
	}

该功能函数传入的位置参数并非一个整数值,而是传入一个迭代器类型,即为一个地址,但需要考虑迭代器是否失效的问题

插入过程中可能会进行增容,而增容进行空间拷贝,原有pos指向的地址失效,对此增容之后,需要更新pos位置,需要在一开始记录pos位置相对于起始位置start的偏移量,方便后续更新pos位置

此时步骤依然与原有插入步骤类似

  • 检测位置
  • 检查容量,考虑是否增容
  • 元素移动(从后向前移动)
  • pos位置插入元素
  • 更新大小

测试结果如下:

  • 任意位置删除

iterator erase(iterator pos)//返回删除后下一个元素位置
	{
		//检查位置
		assert(pos < end() && pos >= begin());
		//移动元素
		iterator it = pos+1;
		while (it <end())
		{
			*(it-1) = *it;
			it++;
		}
		//更新
		_finish--;
		return pos;
	}

删除与插入步骤类似,但不需要进行增容,只需要最后更新大小即可

测试结果如下:

  • resize的实现

void resize(rsize_t n,const T& val=T())
	{
		//n>cap
		if (n > capacity())
		{
			reverse(n);
		}
		if (n > size())//需要填充
		{
			while (_finish != _start + n)
			{
				*_finish = val;
				++_finish;
			}
		}
		//n<cap
		_finish = _start + n;
	}

resize的实现考虑三种情况,简单的n<容量,更新尾指针即可  如果n>容量需要增容,同时需要填充,以传入字符进行依次填充

  • 迭代器的实现

iterator begin()
	{
		return _start;
	}

	const_iterator begin() const
	{
		return _start;
	}

	iterator end()
	{
		return _finish;
	}

	const_iterator end() const
	{
		return _finish;
	}

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

	const T& operator[](size_t pos) const
	{
		assert(pos < size());
		return _start[pos];
	}
  • 打印模板函数实现

template <class T>
void printfvector(vector<T>& vec,const T& val)
{
	typename vector<T>::iterator it = vec.begin();
	while (it != vec.end())
	{
		cout << *it << " ";
		*it = val;
		it++;
	}

}
template <class T>
void printfvector(vector<T>& vec)
{
	typename vector<T>::const_iterator it = vec.begin();
	while (it != vec.end())
	{
		cout << *it << " ";
		//*it = val;
		it++;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HT . WANG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值