Use the library to build a list wheel [C++]

The mock implementation of list

default member function

Constructor

list is a headed bidirectional circular linked list. When constructing a list object, a new head node is required, and its prev and next points to itself.

  	void empty_init()
		{
    
    
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
			_size = 0;

		}
	//默认构造
		list()
		{
    
    
			empty_init();
		}

copy constructor

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

assignment operator overloading

Version 1 (recommended):
The parameter does not use references, let the compiler automatically call the copy constructor of the list to construct a list object, and then call the swap function to exchange the original container with the list object

Doing so is equivalent to handing over the data that should be cleaned up by clear to the container lt through the exchange function, and when the assignment operator overloading function call ends, the container lt will be automatically destroyed and its destructor will be called to clean up.


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

Version 2:
First call the clear function to clear the original container, and then insert the data in the container lt into the empty container one by one by traversal.

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

destructor

When destructing the object, first call the clear function to clear the data in the container, then release the head node, and finally set the head pointer to empty

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

			}
			_size = 0;
		}

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

iterator

Why do iterators exist?

Iterators for strings and vectors

string and vector store data in a continuous memory space , then you can perform operations such as auto-increment, auto-decrement, and dereference through pointers, and you can perform a series of operations on the data at the corresponding location, so string and vector are natural iterators

insert image description here

The position of each node in the memory of the iterator list of the list is random and not necessarily continuous. We cannot operate on the data of the corresponding node only through operations such as self-increment, self-decrement, and dereference of the node pointer . ,Using a class to encapsulate the iterator, inside the iterator class, overload the operators that ++, --, *, ->, !=, == these iterators will use

insert image description here

const_iterator

In a const iterator, the content pointed to by the const iterator cannot be modified. That is, the value returned by dereference cannot be modified. The iterator itself can be modified. There are two solutions:
1. Encapsulate a const iterator class

	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 Choose to add template parameters and reuse code (recommended)

template<class T, class Ref, class Ptr>

insert image description here

The c++ library is the solution

	//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;
	};

When we define a const object, the const modified iterator is automatically called. When calling a const-decorated iterator, the template parameter of __list_iterator is instantiated as a const T&. In fact, when instantiating, const and non-const are still two different classes, but the code work of instantiation is handed over to the compiler.

begin and end

For the list, the iterator of the first valid data is the node after the head node. The
begin function returns the iterator of the first valid data, that is, the next position of the head node.
The end function returns the last valid data. iterator to the next position, i.e. the head node

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

The begin function and end function of const object

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

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

insert

insert image description here

Re-change the link relationship between prev newnode cur

 	//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

insert image description here
Change the link relationship between prev and next, and then release cur

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);
		}

swap

The swap function is used to exchange two containers. The list container stores the head pointer and size of the linked list. We exchange the head pointer and size of the two containers.

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

Note: To call the swap template function in the library here, you need to add "std::" before the swap function to tell the compiler to look for the swap function in the C++ standard library, otherwise the compiler will think that you are calling the swap that is being implemented function (proximity principle)

Summarize

insert image description here

full code

#pragma once
#include<iostream>
#include<assert.h>
#include<list>
using namespace std;
namespace cxq
{
    
    
	//list类存储的数据是任意类型,所以需要设置模板参数
	template<class T>
	//节点
	struct list_node
	{
    
    

		//构造函数
		list_node(const T& val = T()) //缺省值是匿名对象,c++对内置类型进行了升级
			:_prev(nullptr)
			, _next(nullptr)
			, _val(val)
		{
    
    
			
		}

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

	//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>
	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;
	//};


	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;//const 迭代器


		//迭代器 
		//能直接显示构造最好显式构造,不要把决定权给编译器进行单参数的隐式类型转换
		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)
		{
    
    
			找尾
			//Node* tail = _head->_prev;
			//Node* newnode = new Node(x);
			改变链接关系 
			///*newnode = tail->next;*/
			//tail->_next = newnode;
			//newnode->_prev = tail;

			//_head->_prev = newnode;
			//newnode->_next = _head;

			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;
	};
	void test_list1()
	{
    
    
		list<int> lt1;
		lt1.push_back(1);
		lt1.push_back(2);

		list<int>::iterator it = lt1.begin();//拷贝构造
		while (it != lt1.end())
		{
    
    
			cout << *it << " ";
			it++;
		}
		cout << endl;
	}
	void test_list2()
	{
    
    
		list<int> lt1;
		lt1.push_back(1);
		lt1.push_back(2);

		list<int> lt2 (lt1);
		for (auto e : lt1)
		{
    
    
			cout << e << " ";
		}
		cout << endl;
	}
}



If you think this article is helpful to you, you might as well move your fingers to like, collect and forward, and give Xi Ling a big attention. Every support from you will be transformed into the driving force for me to move forward! ! !

Guess you like

Origin blog.csdn.net/qq_73478334/article/details/132189416