STL学习-自模拟实现list

自模拟实现list

公有及私有成员预览

#pragma once
namespace carl
{
	template<class T>
	struct list_node
	{
		list_node<T>* _prev;
		list_node<T>* _next;
		T _data;
		//构造结点
		list_node(const T& x=T() )
			:_prev(nullptr),
			_next(nullptr),
			_data(x)
		{}
	};
	template<class T>
	class list
	{
		typedef list_node<T> Node;
	public:
		typedef  __list_iterator<T> iterator;
		//迭代器相关
		iterator begin();
		iterator end();
		const_iterator begin();const
		const_iterator end();const

		//默认成员函数
		list();
		list(const list<T>& lt);
		list<T>& operator=(list<T> x);
		~list();
        
		//容量相关
		   size_t size();const
			bool empty();
		//访问相关	
		   T& front();
		   T& back();
		//修改相关
		   void push_front(const T& val);
		   void pop_front();

		   void push_back(const T& val);
		   void pop_back();

		   iterator insert(iterator position, const T& val);
		   iterator erase(iterator position);
		   void clear();
	private:
		Node* _head;	
	};
}

必读!

知识梳理:(双向带头循环)链表的结构由若干个结点构成,而结点则是由前驱指针,数据元素,后驱指针构成,因此将结点封装为结构体保证其能够被访问(类也行),并且结点需要提供构造函数,配合new(自动调用构造)来完成链表的初始化工作,而链表本身的操控是由一个结点指针头指针完成的,简称哨兵位,通过哨兵位来完成函数接口的实现。链表最重要且有难度的部分在于迭代器,因此我们先讲述迭代器相关部分!

注意:自模拟实现过程其实就是打开大门的过程,使用的时候是什么样的我们就根据样子来将其模拟完成

image-20230612203627148

迭代器

正向迭代器

我们一步一步打开迭代器的大门,迭代器有正向迭代器,const迭代器以及反向迭代器,我们先从正向迭代器出发一步步探索:

前面学习中,迭代器一般是数据类型的指针,而由于vector,string是连续存储的结构,因此++等操作并不需要重载,直接地址+1就能找到下一个位置的迭代器,但链表不同,链表的结构使其不能使用库中的++操作,(因为你根本不知道此结点的地址在哪里,不像vector容器一样只需要知道第一个元素的地址就能知道所有的,链表是非连续存储单元),因此为了使链表的迭代器也能通过++来到下一个结点的迭代器位置,我们需要完成重载操作,(链表的迭代器本质上是一个结构体指针),因此我们需要将迭代器封装成一个类或结构体。

	template<class T,class Ref,class Ptr>
	struct __list_iterator
	{
		typedef list_node<T>* link_type;
		typedef __list_iterator<T,Ref,Ptr> self;

		//构造
		__list_iterator(link_type x) :_node(x) {}
		__list_iterator(){}
		__list_iterator(const self& x):_node(x._node){}

		//迭代器运算符重载
		bool operator==(const self& x)const
		{
			return _node == x._node;
		}
		bool operator!=(const self& x)const
		{
			return _node != x._node;
		}
		Ref operator*()
		{
			return _node->_data;
		}
		Ptr operator->()
		{
			return &(operator*());
		}
		//前置++	
		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		//后置++
		self operator++(int)
		{
			self tmp(*this);
			_node = _node->next;
			return tmp;
		}
		//前置--
		self& operator--()
		{
			_node = _node->prev;
			return *this;
		}
		//后置--
		self operator--(int)
		{
			self tmp(*this);
			_node = _node->prev;
			return tmp;
		}
	public:
		link_type _node;
	};

注意:可以结合源代码来完成,加强读文档技能的同时还能思考大佬们实现时的思路

const迭代器

const迭代器和正向迭代器的区别在于重载 * 和 重载 ->,若我们有一个const类型的迭代器,若不对迭代器做修改直接 进行解引用或-> 操作的话是无法完成的,因为涉及了权限的放大!

但是如何做此修改呢?

思路一:重载

但是传引用和传const引用是无法重载的,因此不可行

思路二:实现两个迭代器类

虽然可行但是破坏了可读性和简洁性

因为只涉及传引用和传const引用,传指针和传const指针问题,那么有没有一种方式能够改变这两个返回值呢?别忘了,C++可是泛型编程!因此,我们可以传模板参数来达到此目的!

template<class T,class Ref,class Ptr>
	struct __list_iterator
	{
		typedef list_node<T>* link_type;
		typedef __list_iterator<T,Ref,Ptr> self;

		link_type _node;//迭代器本质为结构体指针
        //模板参数 Ref
		Ref operator*()
		{
			return _node->_data;
		}
        //模板参数 Ptr
		Ptr operator->()
		{
			return &(operator*());
		}
	};
template<class T>
	class list
	{
		typedef list_node<T> Node;
	public:
        //const迭代器就传const模板,非const迭代器就传非const模板
		typedef  __list_iterator<T,T&,T*> iterator;
		typedef  __list_iterator<T, const T&, const T*> const_iterator;

对于 反向迭代器,我们在学习完stack和queue后再来实现,因为涉及适配器的内容!

迭代器相关

//迭代器相关
		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);
		}

默认成员函数

//默认成员函数
	//构造函数
		list()
			{	
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
			}
	//析构函数
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}
	//拷贝构造
		list(const list<T>& lt)
		{
			_head= new Node;
			_head->_next = _head;
			_head->_prev = _head;
			for (const auto& e : lt)
			{
				push_back(e);
			}
		}
	//交换函数,交换两个链表数据
		void swap(list<T>& lt)
		{
			::swap(_head, lt._head);
		}
	//赋值运算符重载
		list<T>& operator=(list<T> x)
		{
			swap(x);
			return *this;
		}

容量相关

//容量相关
		   size_t size()const
		   {
			   auto it = begin();
			   size_t i = 0;
			   while (it != end())
			   {
				   i++;
				   it++;
			   }
			   return i;
		   }
		   bool empty()
		   {
			   return begin() == end();
			}

访问相关

//访问相关
		   T& front()
		   {
			   return _head->_next->_data;
		   }
		   T& back()
		   {
			   return _head->_prev->_data;
		   }

修改相关

		//头插
            void push_front(const T& val)
		   {
			   insert(begin(), val);
		   }
		//头删
		   void pop_front()
		   {
			   erase(begin());
		   }
		//尾插
		   void push_back(const T& val)
		   {
			   insert(end(), val);
		   }
		//尾删
		   void pop_back()
		   {
			   erase(--end());
		   }
		//插入函数
		   iterator insert(iterator position, const T& val)
		   {
			   Node* cur = position._node;
			   Node* cur_prev = cur->_prev;

			   Node* newnode = new Node(val);

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

			   return iterator(newnode);
		   }
		//删除函数
		   iterator erase(iterator position)
		   {
			   assert(position != end());
			   Node* cur = position._node;
			   Node* prev = cur->_prev;
			   Node* next = cur->_next;
			   prev->_next = cur->_next;
			   next->_prev = cur->_prev;
			   delete cur;
			   return iterator(next);
		   }
		   //清除数据
		   void clear()
		   {
			   auto it = begin();
			   while (it != end())
			   {
				   it = erase(it);
			   }
		   }

tion._node;
Node* prev = cur->_prev;
Node* next = cur->_next;
prev->_next = cur->_next;
next->_prev = cur->_prev;
delete cur;
return iterator(next);
}
//清除数据
void clear()
{
auto it = begin();
while (it != end())
{
it = erase(it);
}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值