list模拟实现

构造函数

list是一个带头双向循环链表,在构建list时,创建一个头节点,让其prev和next都指向自己

list()
		{
			_head = new Node();
			_head->_next = _head;
			_head->_prev = _head;
		}

拷贝构造函数

//拷贝构造函数
list(const list<T>& lt)
{
	_head = new node; //申请一个头结点
	_head->_next = _head; //头结点的后继指针指向自己
	_head->_prev = _head; //头结点的前驱指针指向自己
	for (auto & e : lt) //两个 e都是同一个
	{
		push_back(e); //将容器lt当中的数据一个个尾插到新构造的容器后面
	}
}

赋值重载

版本一(推荐):

不传引用,利用传值传参过程中就是一次拷贝构造(进行了复用)


		list<T> & operator= (list<T>  lt)//右值没有引用传参,间接调用拷贝构造
			//list<T>& operator= (  list<T> * this, list<T>  lt)//右值没有引用传参,间接调用拷贝构造
			// lt1 = lt2
		{
			this->swap(lt);
			return *this; 
		  }

版本二:

传引用

  
list<T>& operator=(const list<T>& lt)
{
	if (this != &lt) //避免自己给自己赋值
	{
		clear(); //清空容器
		for (const auto& e : lt)
		{
			push_back(e); //将容器lt当中的数据一个个尾插到链表后面
		}
	}
	return *this; //支持连续赋值
}

析构函数

析构函数先调用clear函数清空数据,再将头节点进行释放

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

			}
			_size = 0;
		}

		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}

迭代器

string和vector都是将数据存储在一段连续的空间中,可以通过指针的自增,自减,解引用等进行一系列操作,所以string,vector都是天然的迭代器

但是list不一样,list是链式的数据结构不能够通过指针的操作来进行子增减,所以list通过封装迭代器,在迭代器中进行重载来操作链表的自增减

const迭代器

在const迭代器中,const迭代器指向的内容不能被修改。迭代器自身是可以修改的,有两种解决方案:

1,再封装一个const迭代器类

	template< class T>
	//const 迭代器 ,让迭代器指向的内容不能修改, 迭代器本身可以修改
	struct __list_const_iterator
	{
		typedef list_node<T>  Node;

		//构造函数
		__list_const_iterator(Node* node)
			:_node(node)
		{

		}

		const T& operator*()//出了作用域,节点的值还在,用引用
			//const: 返回节点的值,不能修改
		{
			return _node->_val;
		}

		//前置++,返回++之后的值
		__list_const_iterator& operator++()
			//__list_const_iterator& operator++(__list_const_iterator  * this  )
		{
			_node = _node->_next;
			return *this;
		}
		//后置++ ,返回++之前的值
		__list_const_iterator operator++(int)
		{
			__list_const_iterator tmp(*this);
			_node = _node->_next;
			return tmp;// tmp出了作用域就被销毁 ,用传值返回 
		}

		bool operator==(const __list_iterator<T>& it)
		{
			return *this == it._node;
		}
		bool operator!=(const __list_iterator<T>& it)//传值返回,返回的是拷贝,是一个临时对象,临时对象具有常性
		{
			return *this != it._node;
		}
		Node* _node;
	};

2.增加模板参数进行复用

template<class T, class Ref, class Ptr>

c++库就是用这种方式解决的

	//template<class T> //list类存储的数据是任意类型,所以需要设置模板参数
	//普通迭代器
	//Ref是引用 ,Ptr是指针
	template<class T,class Ref,class Ptr>
	struct  __list_iterator
	{
		typedef list_node<T> Node;
		typedef __list_iterator<T, Ref, Ptr>  self;

		//构造函数
		__list_iterator(Node* node)
			:_node(node)
		{

		}

		Ref operator*()
		{
			return _node->_val;
		}

		Ptr operator->()
		{
			return &_node->_val;
		}

		//前置++,返回++之后的值
		self & operator++()
			//__list_iterator<T> & operator++(__list_iterator<T> * this  )
		{
			_node = _node->_next;
			return *this;

		}
		//后置++ ,返回++之前的值
	      self  operator++(int)
			//	__list_iterator<T> operator++( __list_iterator<T> * this ,int)
		{
			self tmp(*this);//拷贝构造
			_node = _node->_next;
			return tmp; // tmp出了作用域就被销毁 ,用传值返回 
		}
		bool operator!= (const self& it)
		{
			return _node != it._node;
		}
		bool operator== (const self & it)
		{
			return _node == it._node;
		}
		Node* _node;
	};
	template<class T>//list类存储的数据是任意类型,所以需要设置模板参数
	class list
	{
		typedef list_node<T>  Node;
	public:
		typedef  __list_iterator<T ,T&,T* >  iterator;
		typedef  __list_iterator<T, const T&, const T * >  const_iterator;
		//迭代器 
		//能直接显示构造最好显式构造,不要把决定权给编译器进行单参数的隐式类型转换
		iterator end()  //最后一个数据的下一个位置,即头节点
		{
			//return _head; // _head的类型是list_node<T>* ,iterator的类型是__list_iterator<T> ,类型不一致,涉及到单参数的构造函数支持隐式类型转换 
			//还可以写成 return iterator(_head);
			return iterator(_head);
		}
		iterator begin()//第一个数据的位置,即头节点的下一个位置
		{
			//return _head->_next;//单参数的构造函数支持隐式类型转换
			//还可以写成 return iterator(_head->_next)
			return iterator(_head->_next);
		}

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

		const_iterator end() const
		{
			return const_iterator(_head);
		}
		//默认构造
		list()
		{
			empty_init();
		}
		// lt2(lt1)
		//还没有实现const_iterator
		list(const list<T>& lt)
		{
			empty_init();
			//拷贝数据
			for (auto & e :lt )//遍历lt
			{
				push_back(e);
			}
		}
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}
		void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
			_size = 0;

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

		list<T> & operator= (list<T>  lt)//右值没有引用传参,间接调用拷贝构造
			//list<T>& operator= (  list<T> * this, list<T>  lt)//右值没有引用传参,间接调用拷贝构造
			// lt1 = lt2
		{
			this->swap(lt);
			return *this; 
		  }


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

			}
			_size = 0;
		}
		void push_back(const T& x)
		{
			insert(end(), x);//在最后一个数据的下一个位置插入
		}
		//pos位置之前插入
		iterator insert(iterator pos, const T& x)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* newnode = new Node(x);
			// prev newnode cur 链接关系
			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = cur;
			cur->_prev = newnode;
			++_size;
			return newnode;
		}
		iterator erase (iterator pos)

		{
			assert(pos != end());
			Node* cur = pos._node;
			Node* next = cur->_next;
			Node* prev = cur->_prev;
			//prev next 
			prev->_next = next;
			next->_prev = prev;

			delete cur;
			--_size;
			return next;
		}

		size_t size()
		{
			return _size;
		}
		void push_front( const T & x )//T可能是vector ,用引用,减少拷贝
		{
			insert(begin(),x);
		}
		void pop_back()
		{
			erase(--end());//end是最后一个数据的下一个位置,需要--,到达最后一个数据,这样才是尾删
		}
		void pop_front()
		{
			erase(begin());
		}
	private:
		Node* _head;
		size_t _size;
	};

begin和end

		iterator end()  //最后一个数据的下一个位置,即头节点
		{
			return _head; // _head的类型是list_node<T>* ,iterator的类型是__list_iterator<T> ,类型不一致,涉及到单参数的构造函数支持隐式类型转换 
			//还可以写成 return iterator(_head);
		}
		iterator begin()//第一个数据的位置,即头节点的下一个位置
		{
			return _head->_next;//单参数的构造函数支持隐式类型转换
			//还可以写成 return iterator(_head->_next)
		}

const对象的begin和end

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

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

insert函数

 	//pos位置之前插入
		iterator insert(iterator pos, const T& x)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* newnode = new Node(x);
			// prev newnode cur 链接关系
			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = cur;
			cur->_prev = newnode;
			++_size;
			return newnode;
		}

erase函数

iterator erase (iterator pos)
		{
			assert(pos != end());
			Node* cur = pos._node;
			Node* next = cur->_next;
			Node* prev = cur->_prev;
			//prev next 
			prev->_next = next;
			next->_prev = prev;
            delete cur ;
			--_size;
			return next;
		}

push_back和pop_back函数

	void push_back(const T& x)
		{
			insert(end(), x);//在最后一个数据的下一个位置插入
		}
	void pop_back()
		{
			erase(--end());//end是最后一个数据的下一个位置,需要--,到达最后一个数据,这样才是尾删
		}

push_front&pop_front函数

		void pop_front()
		{
			erase(begin());
		}
		void push_front( const T & x )//T可能是vector ,用引用,减少拷贝
		{
			insert(begin(),x);
		}

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值