进阶链表——C++list

之前我们了解了C++的顺序表vector容器,今天我们来了解C++的链表容器list(带头双向循环链表)。

一些基础工作

在模拟实现list之前,我们先来看看文档:
在这里插入图片描述
我们重点来看看它的成员有哪些:
在这里插入图片描述我们重点实现增删查改const和非const迭代器
具体的文档:

https://legacy.cplusplus.com/reference/list/list/?kw=list

结点类的定义

我们的链表是由一个一个相互孤立的结点,连接起来形成的链表,在C++里我们也要像在C语言那里一样,定义结点类:
首先我们在头文件里,用命名空间跟库里的list分隔开来:

namespace My_list
{
	template<class T> //泛型编程
	//结点类定义
	struct _list_Node 
	{

	};

	class list //双向循环链表
	{

	};
}

由于结点的内容我们要经常访问我们用struct,因为struct的默认成员是公有的。

namespace My_list
{
	template<class T> //泛型编程
	//结点类定义
	struct _list_Node
	{
		T _data; //数据
		_list_Node<T>* _next; //下一个结点地址
		_list_Node<T>* _prve; //前一个结点地址

		//构造函数初始化
		_list_Node(const T& val = T())//隐式类型转换
			:_data(val)
			, _next(nullptr)
			, _prve(nullptr)
		{

		}
	};

	class list //双向循环链表
	{

	};
}
namespace My_list
{
	template<class T> //泛型编程
	//结点类定义
	struct _list_Node
	{
		T _data; //数据
		_list_Node<T>* _next; //下一个结点地址
		_list_Node<T>* _prve; //前一个结点地址

		//构造函数初始化
		_list_Node(const T& val = T())//隐式类型转换
			:_data(val)
			, _next(nullptr)
			, _prve(nullptr)
		{

		}
	};

	template<class T> //泛型编程
	class list //双向循环链表
	{
		typedef _list_Node<T> _Node; //typedef _list_Node<T>
	private:
		//定义私有成员
		_Node* _head;
		size_t _size;
	};
}

把list的构造函数实现一下(初始化头结点):
写一个empty_list () 初始化头结点:

namespace My_list
{
	template<class T> //泛型编程
	//结点类定义
	struct _list_Node
	{
		T _data; //数据
		_list_Node<T>* _next; //下一个结点地址
		_list_Node<T>* _prve; //前一个结点地址

		//构造函数初始化
		_list_Node(const T& val = T())//隐式类型转换
			:_data(val)
			, _next(nullptr)
			, _prve(nullptr)
		{

		}
	};

	template<class T> //泛型编程
	class list //双向循环链表
	{
		typedef _list_Node<T> _Node; //typedef _list_Node<T>
	public:

		//初始化头结点
		void empty_list()
		{
			_head = new _Node;
			_head->_next = _head;
			_head->_prve = _head;

			_size = 0;
		}

		//构造函数
		list()
		{
			empty_list();
		}
	private:
		//定义私有成员
		_Node* _head;
		size_t _size;
	};
}

顺便实现一下析构函数,为了实现这个功能我们要写一个函数清理链表的所有的数据。为了实现这个功能更方便,还记得我们之前学过的迭代器吗?我们先来实现一个非const迭代器。

非const迭代器

首先list的迭代器和vector的迭代器很不一样,vector的迭代器的底层是连续的指针,所以我们直接可以对vector的迭代器直接加减,但是list是链表,list的指针是不连续的,无法直接加减(否则可能会访问到未开辟的地址。) 所以list的迭代器我们又要用自己封装一下:
我们也用struct来封装list的迭代器:

	template<class T>
	struct __list_itreator
	{
		typedef _list_Node<T> _Node; //typedef _list_Node<T>
		//成员
		_Node* Node;

		//构造函数
		__list_itreator(_Node* head)
			:Node(head)
		{

		}




	};
	template<class T>
	struct __list_itreator
	{
		typedef _list_Node<T> _Node; //typedef _list_Node<T>
		typedef __list_itreator<T> self; //typedef __list_itreator
		//成员
		_Node* Node;

		//构造函数
		__list_itreator(_Node* head)
			:Node(head)
		{

		}

		//实现后置++
		//前置++返回值也是一个迭代器,我们也可以typedef
		self& operator++()
		{
			Node = Node->_next;
			return *this;
		}

		//后置++
		self operator++(int)
		{
			self tmp(Node);
			Node = Node->_next;

			return tmp;
		}

		//前置--
		self& operator--()
		{
			Node = Node->_prve;
			return *this;
		}

		//后置--
		self operator--(int)
		{
			self tmp(Node);
			Node = Node->_prve;

			return tmp;
		}

		//解引用
		T& operator*()
		{
			return Node->_data;
		}

		//重载->
		T* operator->()
		{
			return &Node->_data;
		}

		//!=
		bool operator!=(const self& N)
		{
			return Node != N.Node;
		}

		//==
		bool operator==(const self& N)
		{
			return Node == N.Node;
		}

	};

现在我们写好了迭代器,现在我们来写我们最常写的begin( )end ( )

		typedef __list_itreator<T> iterator; //非const迭代器

		//返回第一个结点
		iterator begin()
		{
			return _head->_next;
		}

		//返回头结点
		iterator end()
		{
			return _head;
		}

clear ( )

现在我们来看看clear ( )函数的文档:
在这里插入图片描述我们来实现一下:

		//clear()
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{

			}
		}

我们while循环里面要写一个删除结点的函数:

erase ( )

在这里插入图片描述我们来实现一下:

		iterator erase(iterator pos)
		{
			_Node* cur = pos.Node;
			_Node* prve = cur->_prve;//保存cur之前的结点
			_Node* next = cur->_next;//保存cur之后的结点

			delete cur;
			prve->_next = next;
			next->_prve = prve;

			--_size;

			return iterator(next);//防止迭代器失效
		}

我们来完善clear ( ):

		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}

list析构函数

现在做好准备工作后,我们可以实现list的析构函数:

		//析构函数
		~list()
		{
			clear();

			delete _head;
			_head = nullptr;
		}

现在给大家看看我们实现的功能:

namespace My_list
{
	template<class T> //泛型编程
	//结点类定义
	struct _list_Node
	{
		T _data; //数据
		_list_Node<T>* _next; //下一个结点地址
		_list_Node<T>* _prve; //前一个结点地址

		//构造函数初始化
		_list_Node(const T& val = T())//隐式类型转换
			:_data(val)
			, _next(nullptr)
			, _prve(nullptr)
		{

		}
	};

	template<class T>
	struct __list_itreator
	{
		typedef _list_Node<T> _Node; //typedef _list_Node<T>
		typedef __list_itreator<T> self; //typedef __list_itreator
		//成员
		_Node* Node;

		//构造函数
		__list_itreator(_Node* head)
			:Node(head)
		{

		}

		//实现后置++
		//前置++返回值也是一个迭代器,我们也可以typedef
		self& operator++()
		{
			Node = Node->_next;
			return *this;
		}

		//后置++
		self operator++(int)
		{
			self tmp(Node);
			Node = Node->_next;

			return tmp;
		}

		//前置--
		self& operator--()
		{
			Node = Node->_prve;
			return *this;
		}

		//后置--
		self operator--(int)
		{
			self tmp(Node);
			Node = Node->_prve;

			return tmp;
		}

		//解引用
		T& operator*()
		{
			return Node->_data;
		}

		//重载->
		T* operator->()
		{
			return &Node->_data;
		}

		//!=
		bool operator!=(const self& N)
		{
			return Node != N.Node;
		}

		//==
		bool operator==(const self& N)
		{
			return Node == N.Node;
		}

	};

	template<class T> //泛型编程
	class list //双向循环链表
	{
		typedef _list_Node<T> _Node; //typedef _list_Node<T>
	public:
		typedef __list_itreator<T> iterator; //非const迭代器

		//返回第一个结点
		iterator begin()
		{
			return _head->_next;
		}

		//返回头结点
		iterator end()
		{
			return _head;
		}
			
		//初始化头结点
		void empty_list()
		{
			_head = new _Node;
			_head->_next = _head;
			_head->_prve = _head;

			_size = 0;
		}

		//构造函数
		list()
		{
			empty_list();
		}

		//析构函数
		~list()
		{
			clear();

			delete _head;
			_head = nullptr;
		}

		//clear()
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}

		iterator erase(iterator pos)
		{
			_Node* cur = pos.Node;
			_Node* prve = cur->_prve;//保存cur之前的结点
			_Node* next = cur->_next;//保存cur之后的结点

			delete cur;
			prve->_next = next;
			next->_prve = prve;

			--_size;

			return iterator(next);//防止迭代器失效
		}
	private:
		//定义私有成员
		_Node* _head;
		size_t _size;
	};
}

现在我们来测试一下:

	void test1()
	{
		list<int> l;
	}

在这里插入图片描述
编译器正常运行,说明运行成功了。

push_back ( )

在这里插入图片描述我们push_back ( )写起来不难但是,我们可以写好了insert直接复用:

insert ( )

我们用迭代器来完成插入动作:

		//插入
		iterator insert(iterator pos,const T& val)
		{
			_Node* cur = pos.Node;
			//保存之前的结点
			_Node* prve = cur->_prve;

			//开辟结点
			_Node* newnode = new _Node(val);

			//改变指向
			newnode->_prve = prve;
			prve->_next = newnode;

			newnode->_next = cur;
			cur->_prve = newnode;

			++_size;

			return iterator(newnode); //返回插入的位置
		}

现在我们来实现push_back()

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

我们来测试一下:

	void test1()
	{
		list<int> l;
		l.push_back(90);
		l.push_back(90);
		l.push_back(90);
		l.push_back(90);
		l.push_back(90);
		l.push_back(90);

		auto it = l.begin();
		while (it != l.end())
		{
			if (it != -- l.end())
			{
				cout << *it << "<=>";
				it++;
			}
			else
			{
				cout << *it ;
				it++;
			}
		}
		cout << endl;
	}

同时我们还有一个函数:push_front:

push_front ( )

在这里插入图片描述
我们也用insert复用:

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

我们来测试一下:

	void test1()
	{
		list<int> l;
		l.push_back(90);
		l.push_back(190);
		l.push_back(290);
		l.push_back(390);
		l.push_back(490);
		l.push_back(590);

		l.push_front(1234);
		auto it = l.begin();
		while (it != l.end())
		{
			if (it != -- l.end())
			{
				cout << *it << "<=>";
				it++;
			}
			else
			{
				cout << *it ;
				it++;
			}
		}
		cout << endl;
	}

在这里插入图片描述

pop_back()和 pop_front()

在这里插入图片描述在这里插入图片描述这两个函数我们直接复用erase:

		void pop_back()
		{
			erase(--end());//最后一个节点
		}

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

测试一下:

	void test1()
	{
		list<int> l;
		l.push_back(90);
		l.push_back(190);
		l.push_back(290);
		l.push_back(390);
		l.push_back(490);
		l.push_back(590);

		l.push_front(1234);

		l.pop_back();
		l.pop_front();
		auto it = l.begin();
		while (it != l.end())
		{
			if (it != -- l.end())
			{
				cout << *it << "<=>";
				it++;
			}
			else
			{
				cout << *it ;
				it++;
			}
		}
		cout << endl;
	}

在这里插入图片描述

const迭代器

到现在我们还没有实现const迭代器,我们来实现const迭代器(注意const迭代器是指被指向的内容无法被修改,不是指针本身不能被改。)
大家可以这样理解,非const迭代器和const迭代器本质就是两个不同的迭代器,只不过一个的对象是非const对象,另一个的对象是const对象:
所以我们写const迭代器就是重新写一个对象是const的迭代器:

	//const迭代器
	template<class T>
	struct __list_const_itreator
	{
		typedef _list_Node<T> _Node; //typedef _list_Node<T>
		typedef __list_const_itreator<T> self; //typedef __list_itreator
		//成员
		_Node* Node;

		//构造函数
		__list_const_itreator(_Node* head)
			:Node(head)
		{

		}

		//实现后置++
		//前置++返回值也是一个迭代器,我们也可以typedef
		self& operator++()
		{
			Node = Node->_next;
			return *this;
		}

		//后置++
		self operator++(int)
		{
			self tmp(Node);
			Node = Node->_next;

			return tmp;
		}

		//前置--
		self& operator--()
		{
			Node = Node->_prve;
			return *this;
		}

		//后置--
		self operator--(int)
		{
			self tmp(Node);
			Node = Node->_prve;

			return tmp;
		}

		//解引用
		const T& operator*() 
		{
			return Node->_data;
		}

		//重载->
		const T* operator->()
		{
			return &Node->_data;
		}

		//!=
		bool operator!=(const self& N)
		{
			return Node != N.Node;
		}

		//==
		bool operator==(const self& N)
		{
			return Node == N.Node;
		}

	};

但大家发现除了“ * ” 和 “ -> ”运算符的返回值不同,其他的都一样,再重复写,代码有点冗余,这个时候我们可以又用模板:

	//定义T&返回值为Ref,定义T*返回值Ptr
	template<class T, class Ref, class Ptr>
	struct __list_itreator
	{
		typedef _list_Node<T> _Node; //typedef _list_Node<T>
		typedef __list_itreator<T,Ref,Ptr> self; //typedef __list_itreator
		//成员
		_Node* Node;

		//构造函数
		__list_itreator(_Node* head)
			:Node(head)
		{

		}

		//实现后置++
		//前置++返回值也是一个迭代器,我们也可以typedef
		self& operator++()
		{
			Node = Node->_next;
			return *this;
		}

		//后置++
		self operator++(int)
		{
			self tmp(Node);
			Node = Node->_next;

			return tmp;
		}

		//前置--
		self& operator--()
		{
			Node = Node->_prve;
			return *this;
		}

		//后置--
		self operator--(int)
		{
			self tmp(Node);
			Node = Node->_prve;

			return tmp;
		}

		//解引用
		Ref operator*()
		{
			return Node->_data;
		}

		//重载->
		Ptr operator->()
		{
			return &Node->_data;
		}

		//!=
		bool operator!=(const self& N)
		{
			return Node != N.Node;
		}

		//==
		bool operator==(const self& N)
		{
			return Node == N.Node;
		}

	};

这时候我们就很简单了:

		typedef __list_itreator<T, T&, T*> iterator; //非const迭代器
		typedef __list_itreator<T, const T&, const T*> 
			const_iterator; //const迭代器

拷贝构造函数list(const list& It)

有了const迭代器,我们就可以实现拷贝构造函数list(const list& It)

		//拷贝构造
		list(const list<T>& lt)
		{
			empty_list();
			for (auto e : lt)
			{
				push_back(e);
			}
		}
	void test2()
	{
		list<int> l;
		l.push_back(90);
		l.push_back(190);
		l.push_back(290);
		l.push_back(390);
		l.push_back(490);
		l.push_back(590);

		list<int> lt(l);

	}

在这里插入图片描述附上源码:

#pragma once
#include<iostream>
using namespace std;

namespace My_list
{
	template<class T> //泛型编程
	//结点类定义
	struct _list_Node
	{
		T _data; //数据
		_list_Node<T>* _next; //下一个结点地址
		_list_Node<T>* _prve; //前一个结点地址

		//构造函数初始化
		_list_Node(const T& val = T())//隐式类型转换
			:_data(val)
			, _next(nullptr)
			, _prve(nullptr)
		{

		}
	};

	//定义T&返回值为Ref,定义T*返回值Ptr
	template<class T, class Ref, class Ptr>
	struct __list_itreator
	{
		typedef _list_Node<T> _Node; //typedef _list_Node<T>
		typedef __list_itreator<T,Ref,Ptr> self; //typedef __list_itreator
		//成员
		_Node* Node;

		//构造函数
		__list_itreator(_Node* head)
			:Node(head)
		{

		}

		//实现后置++
		//前置++返回值也是一个迭代器,我们也可以typedef
		self& operator++()
		{
			Node = Node->_next;
			return *this;
		}

		//后置++
		self operator++(int)
		{
			self tmp(Node);
			Node = Node->_next;

			return tmp;
		}

		//前置--
		self& operator--()
		{
			Node = Node->_prve;
			return *this;
		}

		//后置--
		self operator--(int)
		{
			self tmp(Node);
			Node = Node->_prve;

			return tmp;
		}

		//解引用
		Ref operator*()
		{
			return Node->_data;
		}

		//重载->
		Ptr operator->()
		{
			return &Node->_data;
		}

		//!=
		bool operator!=(const self& N)
		{
			return Node != N.Node;
		}

		//==
		bool operator==(const self& N)
		{
			return Node == N.Node;
		}

	};

	const迭代器
	//template<class T>
	//struct __list_const_itreator
	//{
	//	typedef _list_Node<T> _Node; //typedef _list_Node<T>
	//	typedef __list_const_itreator<T> self; //typedef __list_itreator
	//	//成员
	//	_Node* Node;

	//	//构造函数
	//	__list_const_itreator(_Node* head)
	//		:Node(head)
	//	{

	//	}

	//	//实现后置++
	//	//前置++返回值也是一个迭代器,我们也可以typedef
	//	self& operator++()
	//	{
	//		Node = Node->_next;
	//		return *this;
	//	}

	//	//后置++
	//	self operator++(int)
	//	{
	//		self tmp(Node);
	//		Node = Node->_next;

	//		return tmp;
	//	}

	//	//前置--
	//	self& operator--()
	//	{
	//		Node = Node->_prve;
	//		return *this;
	//	}

	//	//后置--
	//	self operator--(int)
	//	{
	//		self tmp(Node);
	//		Node = Node->_prve;

	//		return tmp;
	//	}

	//	//解引用
	//	const T& operator*() 
	//	{
	//		return Node->_data;
	//	}

	//	//重载->
	//	const T* operator->()
	//	{
	//		return &Node->_data;
	//	}

	//	//!=
	//	bool operator!=(const self& N)
	//	{
	//		return Node != N.Node;
	//	}

	//	//==
	//	bool operator==(const self& N)
	//	{
	//		return Node == N.Node;
	//	}

	//};

	template<class T> //泛型编程
	class list //双向循环链表
	{
		typedef _list_Node<T> _Node; //typedef _list_Node<T>
	public:
		typedef __list_itreator<T, T&, T*> iterator; //非const迭代器
		typedef __list_itreator<T, const T&, const T*> 
			const_iterator; //const迭代器

		//返回第一个结点
		const_iterator begin() const
		{
			return _head->_next;
		}

		//返回头结点
		const_iterator end() const
		{
			return _head;
		}

		//返回第一个结点
		iterator begin()
		{
			return _head->_next;
		}

		//返回头结点
		iterator end()
		{
			return _head;
		}
			
		//初始化头结点
		void empty_list()
		{
			_head = new _Node;
			_head->_next = _head;
			_head->_prve = _head;

			_size = 0;
		}

		//拷贝构造
		list(const list<T>& lt)
		{
			empty_list();
			for (auto e : lt)
			{
				push_back(e);
			}
		}

		//构造函数
		list()
		{
			empty_list();
		}

		//析构函数
		~list()
		{
			clear();

			delete _head;
			_head = nullptr;
		}

		//clear()
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}

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

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

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

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

		//插入
		iterator insert(iterator pos,const T& val)
		{
			_Node* cur = pos.Node;
			//保存之前的结点
			_Node* prve = cur->_prve;

			//开辟结点
			_Node* newnode = new _Node(val);

			//改变指向
			newnode->_prve = prve;
			prve->_next = newnode;

			newnode->_next = cur;
			cur->_prve = newnode;

			++_size;

			return iterator(newnode); //返回插入的位置
		}

		iterator erase(iterator pos)
		{
			_Node* cur = pos.Node;
			_Node* prve = cur->_prve;//保存cur之前的结点
			_Node* next = cur->_next;//保存cur之后的结点

			delete cur;
			prve->_next = next;
			next->_prve = prve;

			--_size;

			return iterator(next);//防止迭代器失效
		}
	private:
		//定义私有成员
		_Node* _head;
		size_t _size;
	};

	void test1()
	{
		list<int> l;
		l.push_back(90);
		l.push_back(190);
		l.push_back(290);
		l.push_back(390);
		l.push_back(490);
		l.push_back(590);

		l.push_front(1234);

		l.pop_back();
		l.pop_front();
		auto it = l.begin();
		while (it != l.end())
		{
			if (it != -- l.end())
			{
				cout << *it << "<=>";
				it++;
			}
			else
			{
				cout << *it ;
				it++;
			}
		}
		cout << endl;
	}

	void test2()
	{
		list<int> l;
		l.push_back(90);
		l.push_back(190);
		l.push_back(290);
		l.push_back(390);
		l.push_back(490);
		l.push_back(590);

		list<int> lt(l);

	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值