【list的模拟实现】

list的模拟实现

小杨

list相关类要实现的接口

namespace yang
{
	// List的节点类
	template<class T>
	struct ListNode
	{
		ListNode(const T& val = T());

		ListNode<T>* _prev;
		ListNode<T>* _next;
		T _val;
	};
	//List的迭代器类
	template<class T, class Ref, class Ptr>
	class ListIterator
	{
		typedef ListNode<T> Node;
		typedef ListIterator<T, Ref, Ptr> Self;

		// Ref 和 Ptr 类型需要重定义下,实现反向迭代器时需要用到
	public:
		typedef Ref Ref;
		typedef Ptr Ptr;
	public:
		// 构造
		ListIterator(Node* node = nullptr);

		// 具有指针类似行为
		Ref operator*();
		Ptr operator->();

		// 迭代器支持移动
		Self& operator++();
		Self operator++(int);
		Self& operator--();
		Self operator--(int);
		// 迭代器支持比较
		bool operator!=(const Self& l)const;
		bool operator==(const Self& l)const;
		
		Node* _node;
	};

	//List的反向迭代器类
	template<class Iterator>
	class ReverseListIterator
	{
		// 注意:此处typename的作用是明确告诉编译器,Ref是Iterator类中的一个类型,而不是静态成员变量
		// 否则编译器编译时就不知道Ref是Iterator中的类型还是静态成员变量
		// 因为静态成员变量也是按照 类名::静态成员变量名 的方式访问的
	public:
		typedef typename Iterator::Ref Ref;
		typedef typename Iterator::Ptr Ptr;
		typedef ReverseListIterator<Iterator> Self;
	public:
		// 构造
		ReverseListIterator(Iterator it);

		// 具有指针类似行为
		Ref operator*();
		Ptr operator->();

		// 迭代器支持移动
		Self& operator++();
		Self operator++(int);
		Self& operator--();
		Self operator--(int);
		
		// 迭代器支持比较
		bool operator!=(const Self& l)const;
		bool operator==(const Self& l)const;

		Iterator _it;
	};
	//List类
	template<class T>
	class list
	{
		typedef ListNode<T> Node;

	public:
		// 正向迭代器
		typedef ListIterator<T, T&, T*> iterator;
		typedef ListIterator<T, const T&, const T*> const_iterator;

		// 反向迭代器
		typedef ReverseListIterator<iterator> reverse_iterator;
		typedef ReverseListIterator<const_iterator> const_reverse_iterator;
	public:
		// List的构造
		list();
		list(int n, const T& value = T());

		template <class Iterator>
		list(Iterator first, Iterator last);
		list(const list<T>& l);
		
		list<T>& operator=(list<T> l);
		
		~list();
		

		// List的迭代器
		iterator begin();
		iterator end();
		const_iterator begin()const;
		const_iterator end()const;
		reverse_iterator rbegin();
		reverse_iterator rend();
		const_reverse_iterator rbegin()const;
		const_reverse_iterator rend()const;
		
		// List的容量相关
		size_t size()const;
		bool empty()const;
		void resize(size_t newsize, const T& data = T());
		
		
		// List的元素访问操作
		// 注意:List不支持operator[]
		T& front();
		const T& front()const;
		T& back();
		const T& back()const;
		
		// List的插入和删除
		void push_back(const T& val);
		void pop_back();
		void push_front(const T& val);
		void pop_front();
		
		// 在pos位置前插入值为val的节点
		iterator insert(iterator pos, const T& val;

		// 删除pos位置的节点,返回该节点的下一个位置
		iterator erase(iterator pos);
	
		void clear();
		void swap(bite::list<T>& l);
		
	private:
		void CreateHead();
		
	private:
		Node* _head;
	};
}

List的节点类模拟实现

list在容器中是带头双向循环列表

他由一个一个的节点所构成,而这每一个节点,又由

**(前驱指针_prev、后继指针_next、当前节点值_val)**所构成。

那么因为list由一个一个节点构成,顾名思义,我们调用list的节点类,即能获得一个节点,因为该节点是我们的自定义类型,因此需要我们自己来进行写其的构造函数.

我们初始的节点,前驱节点和后继结点都置为空即可,节点所要存储的值传给_val即可。

	template<class T>
	struct ListNode
	{
		ListNode(const T& val = T());

		ListNode<T>* _prev;
		ListNode<T>* _next;
		T _val;
	};

//注意:这里参数给的是缺省参数,const T& val=T(),即给的缺省参数还是匿名对象,这个的好处就是,如果你存的是自定义类型的对象,那么就会调用自定义类型的默认构造,重点在后面,在C++中,可以认为int等内置类型也有构造。比如说 int k =int();

List的正向和反向迭代器

首先说明,迭代器的实现方式一共有两种

种类 举例
原生态指针 vector
原生态指针封装 list

对于原生态指针来说,他们的底层往往是连续的,能通过指针增减以及解引用操作,就可以对所存储位置的数据进行一系列操作,因此vector当中的迭代器就是原生指针。

但是对于list来说,其各个节点在内存中的位置不确定,并不一定是连续的,因此必须借助迭代器封装 ,对其相应节点运算符进行重载,使得我们可以不用关心他们的底层,就可以实现像原生态指针类似的操作(对所存储位置进行一系列的操作)。例如,当你使用list当中的迭代器进行自增操作时,实际上执行了p = p->next语句,只是你不知道。

我们先看一下正向和反向迭代器的模版参数

迭代器类型 迭代器模版参数
正向迭代器 template<class T, class Ref, class Ptr>
反向迭代器 template

是不是会有些许疑惑,这都是神魔奇怪名字?

让我们把目光放到全局,看到List类的模拟实现中

上图中可以看到,list的模拟实现中,typedef了4个迭代器类型,普通正向迭代器、const正向迭代器、普通反向迭代器、const反向迭代器.

目前了解到的:

我们发现,在正向迭代器类中Ref是引用类型,Ptr是指针类型。然后我们将正向迭代器typedef成了 iterator,将const正向迭代器typedef了const_iterator.而反向迭代器中的模版参数Iterator呢?

会发现,就是我们所想的那样,Iteartor就是刚才正向迭代器typedef后的iterator,也就是说反向迭代器的模版参数用的是正向迭代器,这么做的目的是是反向迭代器可以用正向迭代器的元素。

因为在正向迭代器中有以下代码

	// Ref 和 Ptr 类型需要重定义下,实现反向迭代器时需要用到
public:
	typedef Ref Ref;
	typedef Ptr Ptr;

这就意味反向迭代器可以用到正向迭代器中的Ref(引用)和Ptr指针。从而复用了代码。

同理,const反向迭代器和cosnt正向迭代器的关系也是如此。只不过多了const修饰,仅此而已。

总结:反向迭代器类依赖于正向迭代器类。反向迭代器类的实现通常会使用正向迭代器类作为其内部成员,通过正向迭代器类的操作来实现反向遍历。尽管反向迭代器依赖于正向迭代器,但它们是独立的类。反向迭代器类封装了正向迭代器类的实例,并通过重载操作符来提供反向遍历的功能。

构造函数

迭代器类实际上就是对节点指针进行了封装,因此其成员变量就只有一个即节点指针。

在方向迭代器类中,实例化了一个正向迭代器,其目的是用来反向迭代器类的实现。

并且反向迭代器的构造函数,应该是要接受一个正向迭代器作为参数,并赋值给成员变量,即我们刚才实例化的那个正向迭代器对象。并且传递这个正向迭代器参数,我们的反向迭代器就可以知道从哪个位置开始进行反向遍历。总的来说:这体现了封装的好处,就是我们通过封装一个正向迭代器实力,然后根据此我们可以利用正向迭代器的功能来实现反向遍历,即反向迭代器类不需要重新实现正向迭代器类的所有功能。

		//正向迭代器构造
		ListIterator(Node* node = nullptr)
			:_node(node);
		{

		}
	// 反向迭代器构造
	ReverseListIterator(Iterator it)
		:_it(it)
	{
	
	}
++运算符的重载
前置++

正向迭代器:将数据自增,然后返回自增后的数据。

反向迭代器:将数据自减,然后返回自减后的数据。

		//正向迭代器
		Self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		//反向迭代器
		Self& operator++()
		{
			--_it;
			return *this;
		}
后置++

正向迭代器:先保存当前节点指针的指向,然后让指针指向下一个,然后返回刚才保存的那个。

反向迭代器:先保存当前节点指针的指向,然后让指针指向前一个,然后返回刚才保存的那个。

		//正向迭代器
		Self operator++(int)
		{
			Self temp(*this);
			_node = _node->_next;
			return temp;
		}
		//反向迭代器
		Self operator++(int)
		{
			Self temp(*this);
			--_it;
			return temp;
		}
- -运算符的重载
前置--

正向迭代器:让节点先向前走一步,然后返回减减后的节点指针

反向迭代器:让节点先向后走一步,然后返回加加后的节点指针

		//正向迭代器
		Self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		//反向迭代器
		Self& operator--()
		{
			++_it;
			return *this;
		}
后置--

正向迭代器:先保存当前节点,然后指向前一个节点,最后返回保存的节点

反向迭代器:先保存当前节点,然后指向后一个节点,最后返回保存的节点

		//正向迭代器
		Self operator--(int)
		{
			Self temp(*this);
			_node = _node->_prev;
			return *this;
		}
		//反向迭代器
		Self operator--(int)
		{
			Self temp(*this);
			++_it;
			return temp;
		}
==运算符重载和!=运算符重载

判断这两个迭代器是否是同一个位置的迭代器。

	//正向迭代器
	bool operator!=(const Self& l)const
	{
		return _node != l._node;
	}
	bool operator==(const Self& l)const
	{
		return _node == l._node;
	}

	//反向迭代器
	bool operator!=(const Self& l)const
	{
		return _it != l._it;
	}
	bool operator==(const Self& l)const
	{
		return _it == l._it;      
	}
*运算符重载

正向迭代器:返回当前节点的数据

反向迭代器:保存当前节点并拷贝一份副本,然后--副本,最后返回。原因:反向迭代器指向的位置实际上是正向迭代器的前一个位置。也就是说,如果正向迭代器_it指向位置i,那么反向迭代器应该返回位置i-1的元素。

		//正向迭代器
		Ref operator*()
		{
			return _node->_val;
		}
		//反向迭代器
		Ref operator*()
		{
			Iterator temp(_it);
			--temp;
			return *temp;
		}
->运算符的重载

正向迭代器:直接返回节点当中所存储数据的地址即可。

反向迭代器:复用operator*()并且取地址就可以。

		//正向迭代器
		Ptr operator->()
		{
			return &_node->_val;
		}
		//反向迭代器
		Ptr operator->()
		{
			return &(operator*());
		}

list的模拟实现

Member functions(成员函数)
默认构造函数

申请一个头节点,然后让前驱和后继指针都指向自己。

		list()
		{
			CreateHead();
		}
		private:
	void CreateHead()
	{
		_head = new Node;
		_head->_next = _head;
		_head->_prev = _head;
	}
n个元素构造

创建头结点,然后遍历n次,逐个插入。

		list(int n, const T& value = T())
		{
			CreateHead();//创建头节点
			for (int i = 0; i < n; ++i)
			{
				push_back(value);//依次尾插
			}
		}
迭代器区间构造

因为可能要构造的类型不同,因此诞生了迭代器区间构造,构造一个包含与[first,last]范围相同数量元素的容器。

cpp 复制代码
template <class Iterator>
list(Iterator first, Iterator last)
{
	CreateHead();
	while (first != last)
	{
		push_back(*first);
		++first;
	}
}
拷贝构造函数

先申请一个头节点,并让前驱指针和后继指针都指向自己,然后将所给容器中的数据,通过遍历的方式一个个尾插到新构造的容器后面.

这里也可以调用迭代器区间构造一个临时对象temp,然后与其进行交换。

		list(const list<T>& l)
		{
			CreateHead();
			//list<T> temp(l.begin(), l.end());
			//swap(temp);
			for (const auto& e : l)
			{
				push_back(e); //将容器lt当中的数据一个个尾插到新构造的容器后面
			}
		}
赋值拷贝构造

不穿引用,通过编译器自动调用list的拷贝构造函数构造一个临时对象,然后调用swap交换。

cpp 复制代码
		list<T>& operator=(list<T> l)
		{
			swap(l);
			return *this;
		}
析构函数

先调用clear函数清理容器当中的数据,然后将头结点释放,并且置空。

		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}
迭代器相关函数

begin(const begin)函数返回的是第一个有效数据的迭代器,end函数返回的是最后一个有效数据的下一个位置的迭代器。

在当前情况下,最开始创建的头节点就是最后一个有效数据的下一个位置,即end,而刚开始创建头结点的下一个元素就是第一个有效元素

		// List的迭代器
		//正向迭代器begin
		iterator begin()
		{
			return iterator(_head->_next);
		}

		iterator end()
		{
			return iterator(_head);
		}
		//const正向迭代器begin
		const_iterator begin()const
		{
			return const_iterator(_head->_next);
		}
		//const正向迭代器end
		const_iterator end()const
		{
			return const_iterator(_head);
		}
		//反向迭代器rbegin
		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}
		//反向迭代器rend
		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}
		//const 反向迭代器rbegin
		const_reverse_iterator rbegin()const
		{
			return const_reverse_iterator(end());
		}
		//const 反向迭代器rend
		const_reverse_iterator rend()const
		{
			return const_reverse_iterator(begin());
		}
capacity(容量相关)
size

从第一个有效数据开始,定义一个变量count来计数,到最后一个有效数据的下一个位置为止。

size_t size()const
{
	Node* cur = _head->_next;
	size_t count = 0;
	while (cur != _head)
	{
		count++;
		cur = cur->_next;
	}

	return count;
}
empty

看当前节点的下一个节点是否是自己,如果是自己,那么就没有有效元素。

		bool empty()const
		{
			return _head->_next == _head;
		}
resize

先看当前有效数据个数,如果当前数据有效个数大于resize所传递的参数,那么就要减少有效数据的个数,

否则,当前有效数据个数小于resize所传递的参数时,尾插。

		void resize(size_t newsize, const T& data = T())
		{
			size_t oldsize = size();
			//如果newsize比oldsize小,那么就要缩小有效数据个数
			if (newsize < oldsize)
			{
				pop_back();
				--oldsize;
			}
			else
			{
				while (oldsize < newsize)
				{
					push_back(data);
					++oldsize;
				}
			}

		}
list的元素访问操作

List不支持operator[ ]

front返回第一个有效数据的值

back返回最后一个有效数据的值

front或者back加上const意思不变,唯一不同的就是权限从可读可写变成了只读。

T& front()
{
	return _head->_next->_val;
}

const T& front()const
{
	return _head->_next->_val;
}

T& back()
{
	return _head->_prev->_val;
}

const T& back()const
{
	return _head->_prev->_val;
}
list的插入和删除
insert

在pos位置前插入值为val的节点

新建一个节点,然后保存插入前的pos位置的节点,然后先将新节点插入,然后相邻节点连接新节点。

		// 在pos位置前插入值为val的节点
		iterator insert(iterator pos, const T& val)
		{
			Node* newnode = new Node(val);
			//当前pos位置的节点
			Node* cur = pos._node;
			//先将新节点插入
			newnode->_prev=cur->_prev;
			newnode->_next = cur;

			newnode->_prev->_next = newnode;
			cur->_prev = newnode;

			return iterator(newnode);
		}
erase

记录当前要删除的节点,然后记录一下当前节点的前一个位置。然后移除要删除的节点。最后释放掉要删除的节点。

		// 删除pos位置的节点,返回该节点的下一个位置
		iterator erase(iterator pos)
		{
			Node* del = pos._node;
			Node* rdel = pos._node->_prev;
			

			del->_prev->_next = del->_next;
			del->_next->_prev = rdel;

			delete del;
			return iterator(rdel->_next);
		}
push_back和pop_back

复用insert和erase

push_back函数就是在头结点前插入结点,而pop_back就是删除头结点的前一个结点。

void push_back(const T& val)
{
	insert(end(), val);
}

void pop_back()
{
	erase(--end());
}
push_front和pop_front

复用insert和erase

push_front函数就是在第一个有效节点前插入结点,而pop_front就是删除第一个有效节点。

void push_front(const T& val)
{
	insert(begin(), val);
}

void pop_front()
{
	erase(begin());
}
clear

删除有效数据。在准备删除有效数据前时,要先将这个有效数据的后一个和头结点的next相连接,然后再删除有效数据的节点,然后继续向下进行。

void clear()
{
	Node* cur = _head->_next;

	// 采用头删除删除
	while (cur != _head)
	{
		_head->_next = cur->_next;
		delete cur;
		cur = _head->_next;
	}

	_head->_next = _head->_prev = _head;
}
swap

调用库函数中的

swap函数用于交换两个容器,list容器当中存储的实际上就只有链表的头指针,我们将这两个容器当中的头指针交换即可。

		void swap(bite::list<T>& l)
		{
			std::swap(_head, l._head);
		}

list模拟实现总代码

#pragma once
#pragma once

#include <iostream>
using namespace std;
#include <assert.h>

namespace yang
{
	// List的节点类
	template<class T>
	struct ListNode
	{
		ListNode(const T& val = T())
			:_prev(nullptr)
			,_next(nullptr)
			,_val(val)
		{}

		ListNode<T>* _prev;
		ListNode<T>* _next;
		T _val;
	};

	/*
	List 的迭代器
	迭代器有两种实现方式,具体应根据容器底层数据结构实现:
	  1. 原生态指针,比如:vector
	  2. 将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下方法:
		 1. 指针可以解引用,迭代器的类中必须重载operator*()
		 2. 指针可以通过->访问其所指空间成员,迭代器类中必须重载oprator->()
		 3. 指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)
			至于operator--()/operator--(int)释放需要重载,根据具体的结构来抉择,双向链表可以向前移动,所以需要重载,如果是forward_list就不需要重载--
		 4. 迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()
	*/
	template<class T, class Ref, class Ptr>
	class ListIterator
	{
		typedef ListNode<T> Node;
		typedef ListIterator<T, Ref, Ptr> Self;

		// Ref 和 Ptr 类型需要重定义下,实现反向迭代器时需要用到
	public:
		typedef Ref Ref;
		typedef Ptr Ptr;
	public:
		// 构造
		ListIterator(Node* node = nullptr)
			:_node(node)
		{

		}

		// 具有指针类似行为
		Ref operator*()
		{
			return _node->_val;
		}
		Ptr operator->()
		{
			return &_node->_val;
		}

		// 迭代器支持移动
		Self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		Self operator++(int)
		{
			Self temp(*this);
			_node = _node->_next;
			return temp;
		}
		Self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}
		Self operator--(int)
		{
			Self temp(*this);
			_node = _node->_prev;
			return *this;
		}
		// 迭代器支持比较
		bool operator!=(const Self& l)const
		{
			return _node != l._node;
		}
		bool operator==(const Self& l)const
		{
			return _node == l._node;
		}
		
		Node* _node;
	};

	template<class Iterator>
	class ReverseListIterator
	{
		// 注意:此处typename的作用是明确告诉编译器,Ref是Iterator类中的一个类型,而不是静态成员变量
		// 否则编译器编译时就不知道Ref是Iterator中的类型还是静态成员变量
		// 因为静态成员变量也是按照 类名::静态成员变量名 的方式访问的
	public:
		typedef typename Iterator::Ref Ref;
		typedef typename Iterator::Ptr Ptr;
		typedef ReverseListIterator<Iterator> Self;
	public:
		// 构造
		ReverseListIterator(Iterator it)
			:_it(it)
		{

		}

		// 具有指针类似行为
		Ref operator*()
		{
			Iterator temp(_it);
			--temp;
			return *temp;
		}
		Ptr operator->()
		{
			return &(operator*());
		}

		// 迭代器支持移动
		Self& operator++()
		{
			--_it;
			return *this;
		}
		Self operator++(int)
		{
			Self temp(*this);
			--_it;
			return temp;
		}
		Self& operator--()
		{
			++_it;
			return *this;
		}
		Self operator--(int)
		{
			Self temp(*this);
			++_it;
			return temp;
		}
		
		// 迭代器支持比较
		bool operator!=(const Self& l)const
		{
			return _it != l._it;
		}
		bool operator==(const Self& l)const
		{
			return _it == l._it;      
		}

		Iterator _it;
	};

	template<class T>
	class list
	{
		typedef ListNode<T> Node;

	public:
		// 正向迭代器
		typedef ListIterator<T, T&, T*> iterator;
		typedef ListIterator<T, const T&, const T*> const_iterator;

		// 反向迭代器
		typedef ReverseListIterator<iterator> reverse_iterator;
		typedef ReverseListIterator<const_iterator> const_reverse_iterator;

	public:
		// List的构造
		list()
		{
			CreateHead();
		}
		list(int n, const T& value = T())
		{
			CreateHead();//创建头节点
			for (int i = 0; i < n; ++i)
			{
				push_back(value);//依次尾插
			}
		}

		template <class Iterator>
		list(Iterator first, Iterator last)
		{
			CreateHead();
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}
		list(const list<T>& l)
		{
			CreateHead();
			//list<T> temp(l.begin(), l.end());
			//swap(temp);
			for (const auto& e : l)
			{
				push_back(e); //将容器lt当中的数据一个个尾插到新构造的容器后面
			}
		}
		
		list<T>& operator=(list<T> l)
		{

			swap(l);
			return *this;
		}
		
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}
		

		// List的迭代器
				// List的迭代器
		iterator begin()
		{
			return iterator(_head->_next);
		}

		iterator end()
		{
			return iterator(_head);
		}

		const_iterator begin()const
		{
			return const_iterator(_head->_next);
		}

		const_iterator end()const
		{
			return const_iterator(_head);
		}

		reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}

		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

		const_reverse_iterator rbegin()const
		{
			return const_reverse_iterator(end());
		}

		const_reverse_iterator rend()const
		{
			return const_reverse_iterator(begin());
		}
		
		// List的容量相关
		size_t size()const
		{
			Node* cur = _head->_next;
			size_t count = 0;
			while (cur != _head)
			{
				++count;
				cur = cur->_next;
			}
			return count;
		}
		bool empty()const
		{
			return _head->_next == _head;
		}
		void resize(size_t newsize, const T& data = T())
		{
			size_t oldsize = size();
			//如果newsize比oldsize小,那么就要缩小有效数据个数
			if (newsize < oldsize)
			{
				pop_back();
				--oldsize;
			}
			else
			{
				while (oldsize < newsize)
				{
					push_back(data);
					++oldsize;
				}
			}

		}
		
		
		// List的元素访问操作
		// 注意:List不支持operator[]
		T& front()
		{
			return _head->_next->_val;
		}

		const T& front()const
		{
			return _head->_next->_val;
		}

		T& back()
		{
			return _head->_prev->_val;
		}

		const T& back()const
		{
			return _head->_prev->_val;
		}
		
		// List的插入和删除
		void push_back(const T& val)
		{
			insert(end(), val);
		}

		void pop_back()
		{
			erase(--end());
		}

		void push_front(const T& val)
		{
			insert(begin(), val);
		}

		void pop_front()
		{
			erase(begin());
		}
		
		// 在pos位置前插入值为val的节点
		iterator insert(iterator pos, const T& val)
		{
			Node* newnode = new Node(val);
			//当前pos位置的节点
			Node* cur = pos._node;
			//先将新节点插入
			newnode->_prev=cur->_prev;
			newnode->_next = cur;

			newnode->_prev->_next = newnode;
			cur->_prev = newnode;

			return iterator(newnode);
		}

		// 删除pos位置的节点,返回该节点的下一个位置
		iterator erase(iterator pos)
		{
			Node* del = pos._node;
			Node* rdel = pos._node->_prev;
			

			del->_prev->_next = del->_next;
			del->_next->_prev = rdel;

			delete del;
			return iterator(rdel->_next);
		}
	
		void clear()
		{
			Node* cur = _head->_next;

			// 采用头删除删除
			while (cur != _head)
			{
				_head->_next = cur->_next;
				delete cur;
				cur = _head->_next;
			}

			_head->_next = _head->_prev = _head;
		}

		void swap(yang::list<T>& l)
		{
			std::swap(_head, l._head);
		}
		
	private:
		void CreateHead()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
		}
		
	private:
		Node* _head;
	};
}


/
 //对模拟实现的list进行测试
 //正向打印链表
template<class t>
void printlist(const yang::list<t>& l)
{
	auto it = l.begin();
	while (it != l.end())
	{
		cout << *it << " ";
		++it;
	}

	cout << endl;
}

// 测试list的构造
void testbitelist1()
{
	yang::list<int> l1;
	yang::list<int> l2(10, 5);
	printlist(l2);

	int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
	yang::list<int> l3(array, array + sizeof(array) / sizeof(array[0]));
	printlist(l3);

	yang::list<int> l4(l3);
	printlist(l4);

	l1 = l4;
	printlist(l1);
}

// pushback()/popback()/pushfront()/popfront()
void testbitelist2()
{
	// 测试pushback与popback
	yang::list<int> l;
	l.push_back(1);
	l.push_back(2);
	l.push_back(3);
	printlist(l);

	l.pop_back();
	l.pop_back();
	printlist(l);

	l.pop_back();
	cout << l.size() << endl;

	// 测试pushfront与popfront
	l.push_front(1);
	l.push_front(2);
	l.push_front(3);
	printlist(l);

	l.pop_front();
	l.pop_front();
	printlist(l);

	l.pop_front();
	cout << l.size() << endl;
}

// 测试insert和erase
void testbitelist3()
{
	int array[] = { 1, 2, 3, 4, 5 };
	yang::list<int> l(array, array + sizeof(array) / sizeof(array[0]));

	auto pos = l.begin();
	l.insert(l.begin(), 0);
	printlist(l);

	++pos;
	l.insert(pos, 2);
	printlist(l);

	l.erase(l.begin());
	l.erase(pos);
	printlist(l);

	// pos指向的节点已经被删除,pos迭代器失效
	cout << *pos << endl;

	auto it = l.begin();
	while (it != l.end())
	{
		it = l.erase(it);
	}
	cout << l.size() << endl;
}

// 测试反向迭代器
void testbitelist4()
{
	int array[] = { 1, 2, 3, 4, 5 };
	yang::list<int> l(array, array + sizeof(array) / sizeof(array[0]));

	auto rit = l.rbegin();
	while (rit != l.rend())
	{
		cout << *rit << " ";
		++rit;
	}
	cout << endl;

	const yang::list<int> cl(l);
	auto crit = l.rbegin();
	while (crit != l.rend())
	{
		cout << *crit << " ";
		++crit;
	}
	cout << endl;
}
相关推荐
若亦_Royi41 分钟前
C++ 的大括号的用法合集
开发语言·c++
ragnwang4 小时前
C++ Eigen常见的高级用法 [学习笔记]
c++·笔记·学习
lqqjuly7 小时前
特殊的“Undefined Reference xxx“编译错误
c语言·c++
冰红茶兑滴水8 小时前
云备份项目--工具类编写
linux·c++
刘好念8 小时前
[OpenGL]使用 Compute Shader 实现矩阵点乘
c++·计算机图形学·opengl·glsl
酒鬼猿8 小时前
C++进阶(二)--面向对象--继承
java·开发语言·c++
姚先生979 小时前
LeetCode 209. 长度最小的子数组 (C++实现)
c++·算法·leetcode
小王爱吃月亮糖9 小时前
QT开发【常用控件1】-Layouts & Spacers
开发语言·前端·c++·qt·visual studio
aworkholic10 小时前
opencv sdk for java中提示无stiching模块接口的问题
java·c++·opencv·jni·opencv4android·stiching
程序员老冯头10 小时前
第十六章 C++ 字符串
开发语言·c++