模拟实现list超详解(C++)

模拟实现list超详解(C++)_第1张图片

各位小伙伴们,大家好!我是bug。今天我们继续学习STL容器中的list:
(代码可能会有一点问题,请各位老铁指正 )

文章目录

  • 一、list的概念
  • 二、list的用法
    • (1)list对象的创建
    • (2)list的遍历
    • (3)迭代器失效问题****
  • 三、list的模拟实现

一、list的概念

list:在C++中list容器是双向带头循环链表,这种结构在数据的插入删除上相比于vector有着极大的优势,其时间复杂度为O(1)。它唯一的缺点就是不支持随机访问,去查找数据只能够通过遍历的方式,而vector可以通过下标进行访问。

二、list的用法

list的常用接口:

construct(构造函数) 用法
list() 构造空list
list (size_type n, const value_type& val = value_type()) 构造包含n个数据为val的list
list (const list& x) 拷贝构造函数
list (InputIterator first, InputIterator last) 用[first, last)区间中的元素构造list
遍历操作 用法
begin 返回第一个元素的iterator
end 返回最后一个元素下一个位置的iterator
rbegin 返回第一个元素的reverse_iterator,即end位置
rend 返回最后一个元素下一个位置的reverse_iterator,即begin位置
操作空间/容量 用法
empty 检测list是否为空,是返回true,否则返回false
size 返回list中有效节点的个数
获得数据 用法
front 返回list的第一个节点中值的引用
back 返回list的最后一个节点中值的引用
修改操作 用法
push_front 在list首元素前插入值为val的元素
pop_front 删除list中第一个元素
push_back 在list尾部插入值为val的元素
pop_back 删除list中最后一个元素
insert 在list position 位置中插入值为val的元素
erase 删除list position位置的元素
swap 交换两个list中的元素
clear 清空list中的有效元素

(1)list对象的创建

list创建对象的方式有很多,比如:
使用默认构造函数
使用带参构造函数
使用拷贝构造函数
使用赋值运算符重载
使用迭代器区间进行构造
创建匿名对象

代码⬇️ ⬇️:

	//无参构造
	list<int> lt1;
	//有参数构造
	list<int> lt2(4, 5);
	//迭代器区间进行构造
	llist<int> lt3(lt2.begin(), lt2.end());
	//拷贝构造
	list<int> lt4(lt3);
	//赋值运算符重载
	list<int> lt5 = lt4;

(2)list的遍历

与vector、string不同,list由于空间不连续,不支持用[]进行访问数据。所以list的遍历方式只有迭代器和范围for两种。

代码⬇️ ⬇️:

	list<int> lt1(4,5);
	//迭代器进行遍历
	list<int>::iterator it = lt1.begin();
	while (it != lt1.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

	//范围for进行遍历
	for (auto e : lt1)
	{
		cout << e << " ";
	}
	cout << endl;

(3)迭代器失效问题****

在list中插入并不存在迭代器失效的问题,因为list的插入不会改变它原有的空间。但是list的删除会造成迭代器失效,而且失效的部分是指向了被删除的空间迭代器,其他部分的迭代器不会有所影响。

和vector一样,erase使用了返回新迭代器的方式来避免失效。

注意❗️ ❗️

迭代器有两种实现方式,具体应根据容器底层数据结构实现:

1. 原生态指针,比如:vector的迭代器就是原生态指针
2. 将原生态指针进行封装,因迭代器使用形式与指针完全相同,因此在自定义的类中必须实现以下方法:

1、指针解引用,重载operator*()
2、 指针->访问其所指空间成员,重载oprator->()
3.、指针可以++向后移动,迭代器类中必须重载operator++()与operator++(int)至于operator–()/operator–(int)释放需要重载,根据具体的结构来抉择,双向链表可以以向前 移动,所以需要重载,如果是forward_list就不需要重载。
4、 迭代器需要进行是否相等的比较,因此还需要重载operator==()与operator!=()

三、list的模拟实现

这里我们来实现一个简易的vector⬇️ ⬇️:

//结点
		_Tp _data;
		_list_node<_Tp>* _next;
		_list_node<_Tp>* _prev;

		//构造函数
		_list_node(const _Tp& val = _Tp())
		
//迭代器
		typedef _list_node<_Tp>  Link_type;
		typedef _list_iterator<_Tp, Ref,Ptr>  self;
		//引用
		typedef Ref reference;
		typedef const Ref const_reference;
		//指针
		typedef Ptr pointer;
		typedef const Ptr const_pointer;
		
		//构造函数
		_list_iterator(Link_type* pnode = nullptr)
		_list_iterator(const self& lt)
		
		//重载
		reference operator*()
		pointer operator->() 
		const_reference operator*()const
		const_pointer operator->()const
		bool operator!=(const self& x)const
		bool operator==(const self& x)const
		self& operator++() 
		self operator++(_Tp) 
		self& operator--()
		self operator--(_Tp) 
		
//list
		typedef _list_node<_Tp>  Link_type;
		typedef _list_iterator<_Tp,_Tp&,_Tp*> iterator;
		typedef _list_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;
		
private:
		Link_type* _head;
		void Creatphead()
		
public:	
		//迭代器
		iterator begin()
		iterator end()
		const_iterator cbegin()const
		const_iterator cend()const
					
		//构造函数				
		_list()		
		template<class InputIterator>
		_list(InputIterator first, InputIterator last)	
		_list(int n, const _Tp& val = _Tp())
		_list(const _list<_Tp>& lt)
		_list& operator=(const _list<_Tp>& lt)

		//插入删除修改
		void push_back(const _Tp& val)		
		void push_front(const _Tp& val)
		void pop_back()
		void pop_front()
		iterator insert(iterator pos, const _Tp& val = _Tp())
		void insert(iterator pos,int n, const _Tp& val )
		template<class InputIterator>
		void insert(iterator pos,InputIterator first, InputIterator last)
		iterator erase(iterator pos)
		iterator erase(iterator first, iterator last)
		
		//其他接口
		bool empty()
		size_t size()const
		void clear()
		void swap(_list<_Tp>& lt)

完整代码⬇️ ⬇️:

#include
#include

using std::cin;
using std::cout;
using std::endl;

namespace lz
{
	//封装结点
	template<class _Tp>
	struct _list_node
	{
	public:
		_Tp _data;
		_list_node<_Tp>* _next;
		_list_node<_Tp>* _prev;

		_list_node(const _Tp& val = _Tp())
			:_data(val)
			,_next(nullptr)
			, _prev(nullptr)
		{}

	};

	//封装迭代器
	template<class _Tp,class Ref,class Ptr>
	struct _list_iterator
	{
		typedef _list_node<_Tp>  Link_type;
		typedef _list_iterator<_Tp, Ref,Ptr>  self;
		//引用
		typedef Ref reference;
		typedef const Ref const_reference;
		//指针
		typedef Ptr pointer;
		typedef const Ptr const_pointer;


		Link_type* _pnode;

		_list_iterator(Link_type* pnode = nullptr)
			:_pnode(pnode)
		{}

		_list_iterator(const self& lt)
			:_pnode(lt._pnode)
		{}

		reference operator*() { return _pnode->_data; }
		pointer operator->() { return &(operator*()); }
		const_reference operator*()const { return _pnode->_data; }
		const_pointer operator->()const { return &(operator*()); }
		
		bool
		operator!=(const self& x)const { return _pnode != x._pnode; }
		bool
		operator==(const self& x)const { return _pnode == x._pnode; }

		//前置自增
		self& operator++() 
		{
			_pnode = _pnode->_next;
			return *this;
		}

		//后置自增
		self operator++(_Tp) 
		{
			Link_type* tmp = _pnode; 
			_pnode = _pnode->_next;
			return tmp;
		}

		//前置自减
		self& operator--()
		{
			_pnode = _pnode->_prev;
			return *this;
		}

		//后置自减
		self operator--(_Tp) 
		{
			Link_type* tmp = _pnode;
			_pnode = _pnode->_prev;
			return tmp;
		}
		
	};

	//封装结点和迭代器
	template<class _Tp>
	struct _list
	{
		typedef _list_node<_Tp>  Link_type;
		typedef _list_iterator<_Tp,_Tp&,_Tp*> iterator;
		typedef _list_iterator<_Tp,const _Tp&,const _Tp*> const_iterator;
	private:
		Link_type* _head;

		void Creatphead()//创建头指针
		{
			_head = new Link_type;
			_head->_next = _head;
			_head->_prev = _head;
		}
	public:

		//迭代器
		iterator begin() { return _head->_next; }
		iterator end() { return _head; }
		const_iterator cbegin()const{ return _head->_next; }
		const_iterator cend()const { return _head; }

		//无参构造
		_list()
		{
			Creatphead();
		}

		//迭代器区间构造
		template<class InputIterator>
		_list(InputIterator first, InputIterator last)
		{
			Creatphead();
			while (first != last)
			{
				push_back(*first);
				first++;
			}
		}

		//int 不能用size_t,否则会撞!!!???
		//类型不一致,会调用上面的模板迭代器区间
		_list(int n, const _Tp& val = _Tp())
		{
			Creatphead();
			while (n)
			{
				push_back(val);
				n--;
			}
		}

		//拷贝构造函数
		_list(const _list<_Tp>& lt)
		{
			Creatphead();
			/*const_iterator it = lt.cbegin();
			while (it != lt.cend())
			{
				push_back(*it);
				it++;
			}*/
			
			//现代写法
			_list tmp(lt.cbegin(), lt.cend());
			swap(tmp);
		}
		
		//析构函数
		~_list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}

		//赋值运算符重载
		_list<_Tp>& operator=(const _list<_Tp>& lt)
		{
			_list<_Tp> tmp(lt);
			swap(tmp);
		}

		//尾插
		void push_back(const _Tp& val)
		{
			//Link_type* new_node = new Link_type;
			//new_node->_data = val;

			之前的尾
			//Link_type* tail = _head->_prev;

			//tail->_next = new_node;
			//new_node->_prev = tail;
			//new_node->_next = _head;
			//_head->_prev = new_node;


			//代码复用
			insert(end(), val);
		}

		//头插
		void push_front(const _Tp& val)
		{
			//Link_type* new_node = new Link_type;
			//new_node->_data = val;
			//Link_type* pnext = _head->_next;

			连接结点
			//_head->_next = new_node;
			//new_node->_prev = _head;
			//new_node->_next = pnext;
			//pnext->_prev = new_node;

			//代码复用
			insert(begin(), val);
		}

		//尾删
		void pop_back()
		{
		/*	
			if (!empty())
			{
				Link_type* last = _head->_prev;
				Link_type* prev = last->_prev;

				prev->_next = _head;
				_head->_prev = prev;

				delete last;
			}*/

			//代码复用
			erase(--end());
		}

		//头删
		void pop_front()
		{
		/*	if (!empty())
			{
				Link_type* first = _head->_next;
				Link_type* second = first->_next;

				_head->_next = second;
				second->_prev = _head;

				delete first;
			}*/
			
			//代码复用
			erase(begin());
		}

		//任意位置插入一个数据
		iterator insert(iterator pos, const _Tp& val = _Tp())
		{
			Link_type* new_node = new Link_type;
			new_node->_data = val;
			Link_type* pprev = pos._pnode->_prev;

			//插入新节点
			pprev->_next = new_node;
			new_node->_prev = pprev;
			new_node->_next = pos._pnode;
			pos._pnode->_prev = new_node;

			return pos++;
		}

		//int 不能用size_t,否则会撞!!!???
		//类型不一致,会调用上面的模板迭代器区间
		//任意位置插入多个数据
		void insert(iterator pos,int n, const _Tp& val )
		{
			iterator it = pos;
			while (n)
			{
				it = insert(it, val);
				n--;
			}
		}

		//任意位置插入一个迭代器区间的数据
		template<class InputIterator>
		void insert(iterator pos,InputIterator first, InputIterator last)
		{
			iterator it = pos;
			while (first != last)
			{
				it = insert(it,*first);
				first++;
			}
		}
		//任意位置删除一个数据***
		iterator erase(iterator pos)
		{			
			Link_type* pdel = pos._pnode;	
			Link_type* pnext = pdel->_next;
			Link_type* pprev = pdel->_prev;

			//如果为空就不用进行删除操作,同时不能删除头结点
			if (!empty() && pdel != _head)
			{
				pprev->_next = pnext;
				pnext->_prev = pprev;
				delete pdel;
			}

				return pnext;
		}

		//删除一个迭代器区间的数据[first, last)
		iterator erase(iterator first, iterator last)
		{
			iterator it = first;
			while (it != last)
			{
				it = erase(it);
			}
			return last++;
		}

		//判空
		bool empty()
		{
			return _head->_next == _head;
		}

		//计算个数
		size_t size()const
		{
			size_t count = 0;
			iterator it = begin();
			while (it != end())
			{
				count++;
				it++;
			}
			return count;
		}

		//清除
		void clear()
		{
			erase(begin(), end());
		}

		//交换
		void swap(_list<_Tp>& lt)
		{
			std::swap(_head,lt._head);
		}
	};
}

//打印函数
template<class T>
void PrintCon(const lz::_list<T>& con)
{
	auto it = con.cbegin();
	while (it != con.cend())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;
}

void Test1()//构造函数
{
	//无参构造
	lz::_list<int> lt1;
	PrintCon(lt1);

	//存入多个数据
	lz::_list<int> lt2(4, 5);
	PrintCon(lt2);

	//迭代器区间
	lz::_list<int> lt3(lt2.begin(), lt2.end());
	PrintCon(lt3);

	//拷贝构造
	lz::_list<int> lt4(lt3);
	PrintCon(lt4);

	//=重载
	lz::_list<int> lt5 = lt4;
	PrintCon(lt5);

}

void Test2()//insert+erase(避免迭代器失效)
{
	lz::_list<int> lt1(4, 5);
	lz::_list<int> lt2(4, 1);

	//找到尾,插入数据
	lz::_list_iterator<int, int&, int*> it1 = lt1.end();

	//插入单个数据
	it1 = lt1.insert(it1, '!');
	it1 = lt1.insert(it1, 'a');
	PrintCon(lt1);

	//插入多个数据
	lt1.insert(lt1.begin(), 4, 6);
	PrintCon(lt1);

	//将lt2中的数据插入lt1中
	lt1.insert(it1,lt2.begin(),lt2.end());
	PrintCon(lt1);
;
	//删除任意位置数据
	it1 = lt1.erase(it1);//此时的位置是头结点,不能删除
	it1 = lt1.erase(it1);
	PrintCon(lt1);

	//删除迭代器区间的数据[first, last)
	lt1.erase(lt1.begin(),lt1.end());
	PrintCon(lt1);

}

void Test3()//push_back+push_front+pop_back+pop_front
{
	lz::_list<int> lt1;
	PrintCon(lt1);//无数据打印

	lt1.push_back(2);
	lt1.push_back(1);
	lt1.push_front(3);
	lt1.push_front(4);
	PrintCon(lt1);

	//测试删完后的处理
	lt1.pop_back();
	//lt1.pop_back();
	//lt1.pop_back();
	lt1.pop_front();
	//lt1.pop_front();
	//lt1.pop_front();
	PrintCon(lt1);

}

int main()
{
	Test3();

	return 0;
}

今天的内容到这里就结束了,希望各位小伙伴们能够有所收获,我们下期再见!
模拟实现list超详解(C++)_第2张图片

你可能感兴趣的:(c++)