C++ 实现List

list类设计

template<class _Ty>
class list
{
private:
	struct _Node; //声明结构体
	typedef struct _Node* _Nodeptr; //声明结构体类型指针
	struct _Node
	{
		_Nodeptr _Prev, _Next;
		_Ty _Value;
	};
	struct _Acc;
	struct _Acc
	{
		typedef struct _Node*& _Nodepref; //指针的引用
		typedef _Ty& _Vref; //值的引用
		static _Vref _Value(_Nodeptr _p)
		{
			return (*_p)._Value;
		}
		static _Nodepref _Prev(_Nodeptr _p)
		{
			return (*_p)._Prev;
		}
		static _Nodepref _Next(_Nodeptr _p)
		{
			return (*_p)._Next;
		}
	};

迭代器的使用

迭代器分别有:普通迭代器与常性迭代器

public:
	typedef _Ty value_type;
	typedef _Ty& reference;
	typedef const _Ty& const_reference;
	typedef _Ty* pointer;
	typedef const _Ty* const_pointer;
public:
	class iterator;
	class const_iterator;



	class const_iterator //常性迭代器
	{
	protected:
		_Nodeptr _Ptr;
	public:
		const_iterator(_Nodeptr _P):_Ptr(_P)
		{}
		const_reference operator*()const //常引用进行返回
		{
			return _Acc::_Value(_Ptr);
		}
		const_pointer operator->() 
		{
			return &**this;
		}
		const_iterator& operator++()
		{
			_Ptr = _Acc::_Next(_Ptr);
			return *this;
		}
		const_iterator& operator--()
		{
			_Ptr = _Acc::_Prev(_Ptr);
			return *this;
		}
		const_iterator operator++(int)
		{
			const_iterator tmp = *this;
			++* this;
			return tmp;
		}
		const_iterator operator--(int)
		{
			const_iterator tmp = *this;
			--* this;
			return tmp;
		}
		bool operator==(const const_iterator& _X)const
		{
			return this->_Ptr == _X._Ptr;
		}
		bool operator!=(const const_iterator& _X)const
		{
			return !(*this == _X);
		}
		_Nodeptr _Mynode()const
		{
			return _Ptr;
		}
	
	};

	class iterator:public const_iterator  //is a
	{
	public:
		iterator(_Nodeptr _P) :const iterator(_P) {}
		reference operator*() const
		{
			return _Acc::_Value(_Ptr);
		}
		pointer operator->()const
		{
			return &**this;
		}
		iterator& operator++()
		{
			_Ptr = _Acc::_Next(_Ptr);
			return *this;
		}
		iterator operator++(int)
		{
			iterator tmp = *this;
			++* this;
			return tmp;
		}
		iterator& operator--()
		{
			_Ptr = _Acc::Prev(_Ptr);
			return *this;
		}
		iterator operator--(int)
		{
			iterator tmp = *this;
			--* this;
			return tmp;
		}
		bool operator==(const iterator& _X)const
		{
			return this->_Ptr == _X._Ptr;
		}
		bool operator!=(const iterator & _X)const
		{
			return !(*this == _X);
		}
	};

list类实现

在这里插入图片描述
当我们创建一个链表,此时size大小为0,head指向一个_Node,并且该节点的前驱后继都指向自己

public:
	list()_Head(_Buynode()),_Size(0)
	{}


private:
	_Nodeptr _Head;
	size_t _Size;

	_Nodeptr _Buynode(_Nodeptr _Parg = NULL, _Nodeptr _Narg = NULL) //空间申请
	{
		_Nodeptr _S = (_Nodeptr)malloc(sizeof(_Node));
		_Acc::_Prev(_S) = _Prag == NULL ? _S : _Prag;
		_Acc::_Next(_S) = _Narg == NULL ? _S : _Narg;
		return _S;
	}
	void _Freenode(_Nodeptr P)
	{}	
};

这里会出现一个问题,也就是若构造类为模板类。那么派生类不可以直接使用继承得到的积累数据和方法,需要通过this指针使用,否则会出现“找不到标识符”错误

所以在我们 iterator类 继承 const_iterator类 后,对父类保护成员的使用_Nodeptr _Ptr;,需要加上this指针 this->_Ptr ,或者 const_iterator::_Ptr

通过迭代器进行前插

	iterator insert(iterator _P, const _Ty& val)
	{
		_Nodeptr _S = _P._Mynode();
		_Acc::_Prev(_S) = _Buynode(_Acc::_Prev(_S), _S);//_P的前驱更新为新节点 并且将新结点的前驱后继一同设置完毕
		_S = _Acc::_Prev(_S);//此处将_S指向新结点
		_Acc::_Next(_Acc::_Prev(_S)) = _S; //将新结点的前驱的 _Next 节点设置为新结点
		new(&_Acc::_Value(_S)) _Ty(val);  //_Acc::_Value(_S) = val; 设计类型无法直接赋值
		
		return _P;
	}

上面行代码分别解决了①②③,三个指针的设置,继而只剩下最后一个_Next

之所以使用定位new:若我们list中成员属于设计类型无法直接赋值,需要构建对象进行赋值,在_Value空间地址,构建_Ty类型对象,可以类比为以下

int *p = (int*)malloc(sizeof(int));
new(p) int(12); //在p地址,构建int类型对象

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

尾插与头插方法

void push_front(const _Ty& val)
{
	insert(begin(), val);
}
void push_back(const _Ty& val)
{
	insert(end(), val); 
	//对于双向循环链表,在头结点前插入就是尾插
}

完整代码

list大部分功能进行完善,包括迭代器、插入、删除、交换、列表初始化等等

#pragma once
#include<initializer_list>
namespace zyq
{
template<class T>
void Swap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}

template<class _Ty>
class list
{
protected:
	struct _Node; //声明结构体
	typedef struct _Node* _Nodeptr; //声明结构体类型指针
	struct _Node
	{
		_Nodeptr _Prev, _Next;
		_Ty _Value;
	};
	struct _Acc;
	struct _Acc
	{
		typedef struct _Node*& _Nodepref; //指针的引用
		typedef _Ty& _Vref; //值的引用
		static _Vref _Value(_Nodeptr _p)
		{
			return (*_p)._Value;
		}
		static _Nodepref _Prev(_Nodeptr _p)
		{
			return (*_p)._Prev;
		}
		static _Nodepref _Next(_Nodeptr _p)
		{
			return (*_p)._Next;
		}
	};
public:
	typedef _Ty value_type;
	typedef _Ty& reference;
	typedef const _Ty& const_reference;
	typedef _Ty* pointer;
	typedef const _Ty* const_pointer;
public:
	class iterator;
	class const_iterator;
	friend class iterator;
	friend class const_iterator;


	class const_iterator //常性迭代器
	{
	protected:
		_Nodeptr _Ptr;
	public:
		const_iterator(_Nodeptr _P = NULL):_Ptr(_P)
		{}
		const_reference operator*()const //常引用进行返回
		{
			return _Acc::_Value(_Ptr);
		}
		const_pointer operator->() 
		{
			return &**this;
		}
		const_iterator& operator++()
		{
			_Ptr = _Acc::_Next(_Ptr);
			return *this;
		}
		const_iterator& operator--()
		{
			_Ptr = _Acc::_Prev(_Ptr);
			return *this;
		}
		const_iterator operator++(int)
		{
			const_iterator tmp = *this;
			++* this;
			return tmp;
		}
		const_iterator operator--(int)
		{
			const_iterator tmp = *this;
			--* this;
			return tmp;
		}
		bool operator==(const const_iterator& _X)const
		{
			return this->_Ptr == _X._Ptr;
		}
		bool operator!=(const const_iterator& _X)const
		{
			return !(*this == _X);
		}
		_Nodeptr _Mynode()const
		{
			return _Ptr;
		}
	};

	class iterator :public const_iterator  //is a
	{
	public:
		iterator(_Nodeptr _P = NULL) :const_iterator(_P) {}
		reference operator*() const
		{
			return _Acc::_Value(this->_Ptr);
		}
		pointer operator->()const
		{
			return &**this;
		}
		iterator& operator++()
		{
			this->_Ptr = _Acc::_Next(this->_Ptr);
			return *this;
		}
		iterator operator++(int)
		{
			iterator tmp = *this;
			++* this;
			return tmp;
		}
		iterator& operator--()
		{
			this->_Ptr = _Acc::Prev(this->_Ptr);
			return *this;
		}
		iterator operator--(int)
		{
			iterator tmp = *this;
			--* this;
			return tmp;
		}
		bool operator==(const iterator& _X)const
		{
			return this->_Ptr == _X._Ptr;
		}
		bool operator!=(const iterator & _X)const
		{
			return !(*this == _X);
		}
	};
	iterator begin()
	{
		return iterator(_Acc::_Next(_Head));
	}
	iterator end()
	{
		return iterator(_Head);
	}
	const_iterator begin()const 
	{
		return iterator(_Acc::_Next(_Head));
	}
	const_iterator end()const
	{
		return iterator(_Head);
	}

public:
	list(std::initializer_list<_Ty> list):list() //列表方式初始化
	{
		for (auto& x : list)
		{
			push_back(x);
		}
	}
	list():_Head(_Buynode()),_Size(0)
	{}
	list(size_t count,const _Ty&val) :list()  //c11
	{
		insert(begin(), count, val);
	}
	list(const _Ty* _F, const _Ty* _L) :list()
	{
		insert(begin(), _F, _L);
	}//int ar[10]={12,23,34,45,56,67,78,89,90,100};
	list(const list& _X) :_Head(_Buynode()), _Size(0)
	{
		insert(begin(), _X.begin(), _X.end());
	}
	list& operator=(const list _X)
	{
		if (this == &_X) return *this;
		iterator _F1 = begin();
		iterator _L1 = end();
		const_iterator _F2 = _X.begin();
		const_iterator _L2 = _X.end();
		for (; _F1 != _L1 && _F2 != _L2; ++_F1, ++_F2)
		{
			*_F1 = *_F2;
		}//深拷贝,其中一方结束
		erase(_F1, _L1); //被拷贝结束,拷贝者后面节点删除
		insert(_L1, _F2, _L2); //拷贝者结束,将被拷贝后面节点插入拷贝者
	}
	~list()
	{
		clear();
		_Freenode(_Head);
	}
	iterator insert(iterator _P, const _Ty& val)
	{
		_Nodeptr _S = _P._Mynode();
		_Acc::_Prev(_S) = _Buynode(_Acc::_Prev(_S), _S);//_P的前驱更新为新节点 并且将新结点的前驱后继一同设置完毕
		_S = _Acc::_Prev(_S);//此处将_S指向新结点
		_Acc::_Next(_Acc::_Prev(_S)) = _S; //将新结点的前驱的 _Next 节点设置为新结点
		new(&_Acc::_Value(_S)) _Ty(val);   //_Acc::_Value(_S) = val;
		_Size++;
		return _P;
	}
	iterator insert(iterator _P, size_t count, const _Ty& val)
	{
		while (count--)
		{
			insert(_P, val);
		}
		return _P;
	}
	iterator insert(iterator _P, const_iterator _F, const_iterator _L)
	{
		while (_F++ != _L)
		{
			insert(_P, _Acc::_Value(_F));
		}
	}
	void insert(iterator _P, std::initializer_list<_Ty> list)//使用系统的初始化列表
	{
		for (auto& x : list)
		{
			insert(_P, x);
		}
	}//ilist.insert(ilist.begin(),{12,23,34,45,56,67,78,89,90})

	void push_front(const _Ty& val)
	{
		insert(begin(), val);
	}
	void push_back(const _Ty& val)
	{
		insert(end(), val);
	}
	void pop_front()
	{
		erase(begin());
	}
	void pop_back()
	{
		erase(--end());
	}
	void clear()
	{
		erase(begin(), end());
	}
	void remove(const _Ty& val)
	{
		iterator _F = begin(), _L = end();
		while (_F != _L)
		{
			if (*_F == val)
			{
				erase(_F);
				break;
			}
			_F++;
		}
	}
	void remove_all(const _Ty& val)
	{
		iterator _F = begin(), _L = end();
		while (_F != _L)
		{
			if (*_F == val)
			{
				erase(_F++); //删除后_F会变成失效指针,因为该节点已经被删除
			}
			else
			{
				++_F;
			}
		}
	}
	iterator erase(iterator _P)
	{
		_Nodeptr _S = _P++._Mynode();
		_Acc::_Next(_Acc::_Prev(_S)) = _Acc::_Next(_S);
		_Acc::_Prev(_Acc::_Next(_S)) = _Acc::_Prev(_S);
		(&_Acc::_Value(_S))->~Ty(); //释放节点对应数据  进行析构
		_Freenode(_S);
		return _P;
	}
	iterator erase(iterator _F, iterator _L)
	{
		while (_F != _L)
		{
			erase(_F++);
		}
	}
	void Swap(list& _X)
	{
		zyq::Swap(this->_Head, _X._Head);
		zyq::Swap(this->_Size, _X._Size);

	}

private:
	_Nodeptr _Head;
	size_t _Size;

	_Nodeptr _Buynode(_Nodeptr _Parg = NULL, _Nodeptr _Narg = NULL) //空间申请
	{
		_Nodeptr _S = (_Nodeptr)malloc(sizeof(_Node));
		_Acc::_Prev(_S) = _Parg == NULL ? _S : _Parg;
		_Acc::_Next(_S) = _Narg == NULL ? _S : _Narg;
		return _S;
	}

	void _Freenode(_Nodeptr _P)
	{
		free(_P);
	}	
};
}

就地构造

int main()
{
	std::list<Object> alist;
	Object a(10);
	alist.push_back(a);
	
	return 0;
}

以上程序执行,首先构建一个Object对象,随后拷贝构造一个对象在list中
在这里插入图片描述

int main()
{
	std::list<Object> alist;
	alist.push_back(Object(10));
	alist.emplace_back(12); //就地构建 只创建一次
	
	return 0;
}

通过无名对象进行入队,首先会构建一个对象,然后通过移动拷贝构造将此对象的资源进行转移至链表的value值;而就地构造是直接调动构建函数,在结点位置直接构建对象
在这里插入图片描述
在这里插入图片描述

要明白什么是指针,必须先要弄清楚数据在内存中是如何存储的,又是如何被读取的。 如果在程序中定义了一个变量,在对程序进行编译时,系统就会为这个变量分配内存单元。编译系统根据程序中定义的变量类型分配一定长度的空间。内存的基本单元是字节,一字节有8位。每字节都有一个编号,这个编号就是“地址”,它相当于旅馆的房间号。在地址所标示的内存单元中存放的数据,就相当于在该旅馆房间中居住的旅客。 大家一定要弄清楚“内存单元的地址”和“内存单元的内容”这两个概念的区别,即“房间号”和“房间内所住客人”的区别。在程序中一般是通过变量名来对内存单元进行存取操作的。其实程序经过编译以后已经将变量名转换为变量的地址,对变量值的存取都是通过地址进行的。这种按变量地址存取变量的方式称为直接访问方式。 还有一种间接访问的方式,即变量中存放的是另一个变量的地址。也就是说,变量中存放的不是数据,而是数据的地址。就跟寻宝一样,可能你按藏宝图千辛万苦找到的宝藏不是金银珠宝,而是另一张藏宝图。按C语言的规定,可以在程序中定义整型变量、实型变量、字符型变量,也可以定义这样一种特殊的变量,它是存放地址的。 由于通过地址能找到所需的变量单元,所以可以说,地址“指向”该变量单元。如同一个房间号指向某一个房间一样,只要告诉房间号就能找到房间的位置。因此在C语言中,将地址形象地称为“指针”,意思就是通过它能找到以它为地址的内存单元。 所以,一个变量的地址就称为该变量的指针指针就是地址,而地址就是内存单元的编号。它是一个从零开始的、操作受限的非负整数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值