C++学习之路,从0到精通的征途:vector类的模拟实现

目录

一.vector的介绍

二.vector的接口实现

1.成员变量

2.迭代器

(1)begin

(2)end

3.容量操作

(1)size,capacity

(2)reserve

(3)resize

4.修改

(1)push_back

(2)pop_back

(3)insert

(4)erase

(5)swap

5.默认成员函数

(1)构造函数

(2)拷贝构造函数

(3)析构函数

(4)赋值重载

​三.代码总览

vector.h

test.cpp


一.vector的介绍

源文档

二.vector的接口实现

1.成员变量

vector可以通过类模板来存储不同数据类型的元素,并且由于其存储空间连续,与string相同,其迭代器为空间中该数据类型的指针,

cpp 复制代码
template<class T>
class vector
{
public:
	typedef T* iterator;
	typedef const T* const_iterator;

private:
	iterator _start = nullptr; // 指向空间中第一个有效数据
	iterator _finish = nullptr; // 指向空间中最后一个有效数据的下一个位置
	iterator _end_of_storage = nullptr; // 指向存储空间尾部
};

2.迭代器

(1)begin

cpp 复制代码
iterator begin()
{
	return _start;
}
cpp 复制代码
const_iterator begin() const
{
	return _start;
}

(2)end

cpp 复制代码
iterator end()
{
	return _finish;
}
cpp 复制代码
const_iterator end() const
{
	return _finish;
}

3.容量操作

(1)size,capacity

cpp 复制代码
size_t size() const
{
	return _finish - _start;
}
cpp 复制代码
size_t capacity() const
{
	return _end_of_storage - _start;
}

(2)reserve

cpp 复制代码
void reserve(size_t n)
{
	if (n > capacity())
	{
		// 异地扩容,复制数据,并释放旧空间
		size_t old_size = size();
		T* tmp = new T[n];
		if (_start)
		{
			for (int i = 0; i < old_size; i++)
			{
				tmp[i] = _start[i];
			}
			delete[] _start;
		}

		// 更新成员变量
		_start = tmp;
		_finish = tmp + old_size;
		_end_of_storage = _start + n;
	}
}

当n大于当前容量,则进行扩容操作,当n小于当前容量,不做处理。

(3)resize

cpp 复制代码
// 由于val的数据类型由模板T决定,val的缺省值采用匿名对象
void resize(size_t n, T val = T())

C++中新增了内置类型的构造函数,在声明内置类型变量时,可以进行如下操作:

可以看到内置类型也可以调用其构造,int类型被初始化为0,double类型被初始化为0.0,char类型被初始化为'\0'。

cpp 复制代码
void resize(size_t n, T val = T())
{
	if (n > size())
	{
		// 扩容
		reserve(n);
		// 插入数据
		while (_finish != _start + n)
		{
			*_finish = val;
			++_finish;
		}
		//for (int i = size(); i < n; i++)
		//{
		//	_start[i] = val;
		//}
	
		// 更新_finish
		_finish = _start + n;
	}
	else
	{
		// 删除数据
		_finish = _start + n;
	}
}

当n大于有效数据个数时,扩容并插入数据,当n小于有效数据个数时,直接调整_finish指向的位置,达到删除数据的操作。

4.修改

(1)push_back

cpp 复制代码
void push_back(const T& x)
{
	// 容量不够,进行扩容
	if (_finish == _end_of_storage)
	{
		size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
		reserve(newcapacity);
	}

	*_finish = x;
	++_finish;
}

(2)pop_back

cpp 复制代码
void pop_back()
{
	assert(size() > 0);
	--_finish;
}

(3)insert

vector的insert操作需要考虑在进行异地扩容时,迭代器失效的问题:

所以我们需要在扩容时算出pos相对于当前_start的距离,在扩容后更新pos的位置,使其指向扩容后的空间。

cpp 复制代码
void insert(iterator pos, const T& x)
{
	assert(pos >= _start && pos <= _finish);
	if (_finish == _end_of_storage)
	{
		// 算出pos对_start的相对位置
		size_t len = pos - _start;
		size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
		reserve(newcapacity);
		// 更新pos,指向新空间
		pos = _start + len;
	}
	// 使pos及pos后的元素向后移动一位,插入数据
	iterator end = _finish - 1;
	while (end >= pos)
	{
		*(end + 1) = *end;
		--end;
	}
	*pos = x;
	++_finish;
}

(4)erase

vector的erase操作并没有扩容问题,但由于erase后pos之后的元素会向前移动一位,造成pos指向的位置不明确,如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,从而也会导致迭代器失效:

所以erase需要返回一个指向删除元素的下一个元素的迭代器,才能实现连续删除:

cpp 复制代码
iterator erase(iterator pos)
{
	assert(pos >= _start && pos < _finish);
	iterator end = pos + 1;
	// 删除元素
	while (end < _finish)
	{
		*(end - 1) = *end;
		++end;
	}
	--_finish;
	// 返回删除元素的下一个元素的迭代器
	return pos;
}

(5)swap

cpp 复制代码
void swap(vector<T>& v)
{
	std::swap(_start, v._start);
	std::swap(_finish, v._finish);
	std::swap(_end_of_storage, v._end_of_storage);
}

5.默认成员函数

(1)构造函数

cpp 复制代码
// 成员变量走初始化列表,采用缺省值
vector()
{}

// n个元素初始化
vector(int n, const T& val = T())
{
	reserve(n);
	for (int i = 0; i < n; i++)
	{
		push_back(val);
	}
}

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

// 用迭代器初始化
template <class InputIterator>
vector(InputIterator first, InputIterator last)
{
	while (first != last)
	{
		push_back(*first);
		++first;
	}
}

// initializer_list有自己的迭代器,直接扩容,尾插数据即可
vector(std::initializer_list<T> il)
{
	reserve(il.size());
	for (auto& e : il)
	{
		push_back(e);
	}
}

(2)拷贝构造函数

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

先进行同等大小空间的扩容,遍历被拷贝的链表,再逐个元素遍历尾插即可。

(3)析构函数

cpp 复制代码
~vector()
{
	if (_start)
	{
		delete[] _start;
		_start = _finish = _end_of_storage = nullptr;
	}
}

(4)赋值重载

cpp 复制代码
vector<T>& operator=(vector<T> v)
{
	swap(v);
	return *this;
}

三.代码总览

vector.h

cpp 复制代码
#pragma once
#include<iostream>
#include<assert.h>
#include<initializer_list>
#include<algorithm>

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

		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;
		}

		// 成员变量走初始化列表,采用缺省值
		vector()
		{}

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

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

		// 用迭代器初始化
		template <class InputIterator>
		vector(InputIterator first, InputIterator last)
		{
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		// initializer_list有自己的迭代器,直接扩容,尾插数据即可
		vector(std::initializer_list<T> il)
		{
			reserve(il.size());
			for (auto& e : il)
			{
				push_back(e);
			}
		}

		// 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);
		}

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

		~vector()
		{
			if (_start)
			{
				delete[] _start;
				_start = _finish = _end_of_storage = nullptr;
			}
		}

		// 由于val的数据类型由模板T决定,val的缺省值采用匿名对象
		void resize(size_t n, T val = T())
		{
			if (n > size())
			{
				// 扩容
				reserve(n);
				// 插入数据
				while (_finish != _start + n)
				{
					*_finish = val;
					++_finish;
				}
				//for (int i = size(); i < n; i++)
				//{
				//	_start[i] = val;
				//}
			
				// 更新_finish
				_finish = _start + n;
			}
			else
			{
				// 删除数据
				_finish = _start + n;
			}
		}

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				// 异地扩容,复制数据,并释放旧空间
				size_t old_size = size();
				T* tmp = new T[n];
				if (_start)
				{
					for (int i = 0; i < old_size; i++)
					{
						tmp[i] = _start[i];
					}
					delete[] _start;
				}

				// 更新成员变量
				_start = tmp;
				_finish = tmp + old_size;
				_end_of_storage = _start + n;
			}
		}

		void push_back(const T& x)
		{
			// 容量不够,进行扩容
			if (_finish == _end_of_storage)
			{
				size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
				reserve(newcapacity);
			}

			*_finish = x;
			++_finish;
		}

		void pop_back()
		{
			assert(size() > 0);
			--_finish;
		}

		void insert(iterator pos, const T& x)
		{
			assert(pos >= _start && pos <= _finish);
			if (_finish == _end_of_storage)
			{
				// 算出pos对_start的相对位置
				size_t len = pos - _start;
				size_t newcapacity = capacity() == 0 ? 4 : 2 * capacity();
				reserve(newcapacity);
				// 更新pos,指向新空间
				pos = _start + len;
			}
			// 使pos后的元素向后移动,插入数据
			iterator end = _finish - 1;
			while (end >= pos)
			{
				*(end + 1) = *end;
				--end;
			}
			*pos = x;
			++_finish;
		}

		iterator erase(iterator pos)
		{
			assert(pos >= _start && pos < _finish);
			iterator end = pos + 1;
			// 删除元素
			while (end < _finish)
			{
				*(end - 1) = *end;
				++end;
			}
			--_finish;
			// 返回删除元素的下一个元素的迭代器
			return pos;
		}
	private:
		iterator _start = nullptr;
		iterator _finish = nullptr;
		iterator _end_of_storage = nullptr;
	};
}

test.cpp

cpp 复制代码
#include<vector>
#include"vector.h"
using namespace std;

namespace my_vector
{
	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.push_back(6);

		vector<int> v2(3, 5);

		vector<int> v3 = {1, 2, 3};
		for (auto& e : v3)
		{
			std::cout << e << ' ';
		}

		v2 = v3;
		for (auto& e : v2)
		{
			std::cout << e << ' ';
		}
		std::cout << std::endl;
		for (auto& e : v3)
		{
			std::cout << e << ' ';
		}
	}

	void test_vector2()
	{
		//vector<int> v = { 1 };
		//v.pop_back();
		//v.pop_back();
		vector<int> v = { 1,2,3,4,5,6 };
		v.resize(7, 0);
		for (auto& e : v)
		{
			std::cout << e << ' ';
		}
		std::cout << std::endl;
		v.resize(3);
		for (auto& e : v)
		{
			std::cout << e << ' ';
		}
	}

	void test_vector3()
	{
		vector<int> v = { 1,2,3,4,4,6 };
		v.insert(v.begin() + v.size(), 5);
		for (auto& e : v)
		{
			cout << e << ' ';
		}
		cout << endl;
		vector<int> v1 = { 1 };
		v1.erase(v1.begin());
		for (auto& e : v1)
		{
			cout << e << ' ';
		}
		cout << endl;
		vector<string> v2 = { "11111111111111","11111111111111", "11111111111111" };
		for (auto& e : v2)
		{
			cout << e << ' ';
		}
	}
}

int main()
{
	//my_vector::test_vector3();
	int a = int();
	double b = double();
	char c = char(); // '\0'


	return 0;
}
相关推荐
shengjk12 分钟前
序列化和反序列化:从理论到实践的全方位指南
java·大数据·开发语言·人工智能·后端·ai编程
jimsten4 分钟前
苍穹外卖 - Day02 学习笔记
java·笔记·学习
学习中的码虫15 分钟前
数据结构中的高级排序算法
数据结构·算法·排序算法
passionSnail17 分钟前
《用MATLAB玩转游戏开发》推箱子游戏的MATLAB趣味实现
开发语言·游戏·matlab
人类恶.17 分钟前
C 语言学习笔记(6)
c语言·笔记·学习
山北雨夜漫步20 分钟前
机器学习 Day17 朴素贝叶斯算法-----概率论知识
人工智能·算法·机器学习
Once_day40 分钟前
C++之fmt库介绍和使用(1)
开发语言·c++·fmt
是店小二呀43 分钟前
【优选算法 | 字符串】字符串模拟题精选:思维+实现解析
android·c++·算法
摆烂且佛系1 小时前
FastByteArrayOutputStream和ByteArrayInputStream有什么区别
java·开发语言
不爱学英文的码字机器1 小时前
[操作系统] 策略模式进行日志模块设计
c++·策略模式