C++: list use and simulation implementation

list introduction

  1. list is a class template, adding <type> instantiation is a specific class .
  2. A list is a sequential container that can be inserted and deleted at any position .
  3. The bottom layer of the list is a two-way circular linked list structure . Each element in the linked list is stored in an independent node that is not related to each other, and the previous element and the next element are pointed to by pointers in the node.
  4. Compared with other sequential containers, the biggest defect of list is that it does not support random access at any position . For example, to access the sixth node, it must iterate from a known node to this node.

Diagram of doubly linked list:
Doubly linked list diagram



listCommon interface

1. Structure

function Function
list (size_type n, const value_type& val = value_type()) The constructed list contains n nodes whose value is val
list() Construct an empty list
list (const list& x) copy construction
list (InputIterator first, InputIterator last) Iterator range initialization
(template, iterator range that can be passed to other containers)

2. Iterators

function Function
begin() plus end() Get the iterator/const_iterator of the first data position, get the iterator/const_iterator of the next position of the last data
rbegin() plus rend() Reverse iterator, get the reverse_iterator of the last data position, get the reverse_iterator of the previous position of the first data

3. Capacity

function Function
size() Get the number of valid data
empty() Determine whether it is empty (size is 0 is empty, return true)

4. Access data

function Function
front() Get a reference to the head node data
back() Returns a reference to the tail node data

5. Add, delete, check and modify

function Function
push_front
(const value_type& val)
header data val
push_back
(const value_type& val)
Tail deleted data val
pop_front() head delete
pop_back() tail delete
insert (iterator position, const value_type& val) Insert an element with value val in the position position
erase (iterator position) Delete the element at position
swap(list& x) swap two lists
clear() Clear valid data

6. Iterator invalidation

       Iteration invalidation means that the node pointed to by the iterator is invalid, that is, the node is deleted. Because the underlying structure of the list is a two-way circular linked list with the leading node, the iterator of the list will not be invalidated when it is inserted into the list. It will only be invalidated when it is deleted, and only the iteration pointing to the deleted node will be invalidated. , other iterators are not affected.

#include<iostream>
#include<list>
using namespace std;

//错误代码演示
int main()
{
    
    
	int array[] = {
    
     1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
	list<int> l(array, array + sizeof(array) / sizeof(array[0]));
	auto it = l.begin();
	while (it != l.end())
	{
    
    
		// erase()函数执行后,it所指向的节点已被删除
		//因此it无效,在下一次使用it时,必须先给其赋值
		it = l.erase(it); //只需要去掉++it,这里修改成it = erase(it)即可
		++it;
	}
	return 0;
}



List simulation implementation

1. Implementation of iterators

      Different from vector, the iterator of list is not a native pointer , because what the user needs to get is the data in the node instead of the whole node, and finding the next node cannot be done simply by pointer ++, so it is necessary to put the iterator The controller is separately encapsulated into a class, and the requirements are fulfilled by overloading operators such as *.

namespace MyList
{
    
    
	//节点设计成结构体,方便访问
	template<typename T>
	struct list_node
	{
    
    
		list_node(const T val = T())
			:_data(val)
			, _next(nullptr)
			, _prev(nullptr)
		{
    
    }
		T _data;
		list_node<T>* _next;
		list_node<T>* _prev;
	};

	//迭代器
	//这里设计模板参数除了迭代器,还有Ref(引用)和Ptr(指针)
	//这样设计是为了同时生成普通迭代器和const对象的迭代器
	//普通对象(可读可写):iterator<T, T&, T*>
	//const对象(可读不可写):const_iterator<T, const T&, const T*>
	template<typename T, typename Ref, typename Ptr>
	struct __list_iterator
	{
    
    
		typedef list_node<T> Node;
		typedef __list_iterator<T, Ref, Ptr> self; //要返回迭代器需要返回实例化对象,重命名一下

		Node* _node;

		__list_iterator(Node* p)
			:_node(p)
		{
    
    }

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

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

		//返回指针可以让自定义类型自行打印,访问成员
		//->操作符,比较特殊,it->_num转换出来其实是it.operator->()->_num
		Ptr operator->()
		{
    
    
			return &(_node->_data);
		}

		bool operator!=(const self& s)
		{
    
    
			return _node != s._node;
		}

		bool operator==(const self& s)
		{
    
    
			return _node == s._node;
		}
	};

	//反向迭代器
	//反向迭代器需要进行封装,其实就是复用普通迭代器,然后++和--操作反过来
	
	//普通对象(可读可写):Reverse_iterator<iterator,T&,T*>
	//const对象(可读不可写):Reverse_iterator<const_iterator,const T&,const T*>
	template<class Iterator, class Ref, class Ptr>
	struct Reverse_iterator
	{
    
    
		typedef Reverse_iterator<Iterator, Ref, Ptr> self;
		Iterator _it;

		//构造
		Reverse_iterator(Iterator it)
			:_it(it)
		{
    
    }


		self& operator++()
		{
    
    
			_it--;
			return *this;
		}


		self operator++(int)
		{
    
    
			self tmp(*this);
			_it--;
			return tmp;
		}


		self& operator--()
		{
    
    
			_it++;
			return *this;
		}


		self operator--(int)
		{
    
    
			self tmp(*this);
			_it++;
			return tmp;
		}


		Ref operator*()
		{
    
    
			return *_it;
		}


		Ptr operator->()
		{
    
    
			return _it;
		}


		bool operator!=(const self& s)
		{
    
    
			return _it != s._it;
		}


		bool operator==(const self& s)
		{
    
    
			return _it == s._it;
		}
	};
}

2. Complete code

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

namespace MyList
{
    
    
	//节点设计成结构体,方便访问
	template<typename T>
	struct list_node
	{
    
    
		list_node(const T val = T())
			:_data(val)
			, _next(nullptr)
			, _prev(nullptr)
		{
    
    }
		T _data;
		list_node<T>* _next;
		list_node<T>* _prev;
	};

	//迭代器
	//这里设计模板参数除了迭代器,还有Ref(引用)和Ptr(指针)
	//这样设计是为了同时生成普通迭代器和const对象的迭代器
	//普通对象(可读可写):iterator<T, T&, T*>
	//const对象(可读不可写):const_iterator<T, const T&, const T*>
	template<typename T, typename Ref, typename Ptr>
	struct __list_iterator
	{
    
    
		typedef list_node<T> Node;
		typedef __list_iterator<T, Ref, Ptr> self; //要返回迭代器需要返回实例化对象,重命名一下

		Node* _node;

		__list_iterator(Node* p)
			:_node(p)
		{
    
    }

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

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

		//返回指针可以让自定义类型自行打印,访问成员
		//->操作符,比较特殊,it->_num转换出来其实是it.operator->()->_num
		Ptr operator->()
		{
    
    
			return &(_node->_data);
		}

		bool operator!=(const self& s)
		{
    
    
			return _node != s._node;
		}

		bool operator==(const self& s)
		{
    
    
			return _node == s._node;
		}
	};

	//反向迭代器
	//反向迭代器需要进行封装,其实就是复用普通迭代器,然后++和--操作反过来
	
	//普通对象(可读可写):Reverse_iterator<iterator,T&,T*>
	//const对象(可读不可写):Reverse_iterator<const_iterator,const T&,const T*>
	template<class Iterator, class Ref, class Ptr>
	struct Reverse_iterator
	{
    
    
		typedef Reverse_iterator<Iterator, Ref, Ptr> self;
		Iterator _it;


		Reverse_iterator(Iterator it)
			:_it(it)
		{
    
    }


		self& operator++()
		{
    
    
			_it--;
			return *this;
		}


		self operator++(int)
		{
    
    
			self tmp(*this);
			_it--;
			return tmp;
		}


		self& operator--()
		{
    
    
			_it++;
			return *this;
		}


		self operator--(int)
		{
    
    
			self tmp(*this);
			_it++;
			return tmp;
		}


		Ref operator*()
		{
    
    
			return *_it;
		}


		Ptr operator->()
		{
    
    
			return _it;
		}


		bool operator!=(const self& s)
		{
    
    
			return _it != s._it;
		}


		bool operator==(const self& s)
		{
    
    
			return _it == s._it;
		}
	};

	template<typename T>
	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;
		typedef Reverse_iterator<iterator, T&, T*> reverse_iterator;
		typedef Reverse_iterator< const_iterator, const T&, const T*> reverse_const_iterator;


		//迭代器部分
		iterator begin()
		{
    
    
			return _head->_next;
		}

		iterator end()
		{
    
    
			return _head;
		}

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

		const_iterator end()const
		{
    
    
			return _head;
		}

		reverse_iterator rbegin()
		{
    
    
			return (--end());//_head->_prev
		}

		reverse_iterator rend()
		{
    
    
			return (end());//_head
		}

		reverse_const_iterator rbegin()const
		{
    
    
			return (--end());//_head->_prev
		}

		reverse_const_iterator rend()const
		{
    
    
			return (end());//_head
		}

		/// //
		/// 
	private:
		//不希望外界调用,设计成私有
		void empty_init()
		{
    
    
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
			_size = 0;
		}
	public:
		//构造、析构部分
		list()
		{
    
    
			empty_init();
		}

		list(size_t n, const T& value = T())
		{
    
    
			empty_init();
			while (n--)
			{
    
    
				push_back(value);
			}
		}

		//重载给内置类型使用,整形默认是int,不写这个会优先匹配list(Iterator first, Iterator last)
		list(int n, const T& value = T())
		{
    
    
			empty_init();
			while (n--)
			{
    
    
				push_back(value);
			}
		}

		//迭代器区间初始化
		template <class Iterator>
		list(Iterator first, Iterator last)
		{
    
    
			empty_init();
			while(first != last)
			{
    
    
				push_back(*first);
				first++;
			}
		}

		list(const list<T>& lt)
		{
    
    
			empty_init();
			for (auto e : lt)
			{
    
    
				push_back(e);
			}
		}

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


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

		//使用传之传参,直接拷贝一份交换操作的底层空间就好
		list<T>& operator=(list<T> lt)
		{
    
    
			swap(lt);
			return *this;
		}

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

	
		/// /
		/

		//访问头,尾数据
		T& front()
		{
    
    
			return _head->_next->_data;
		}

		const T& front()const
		{
    
    
			return _head->_next->_data;
		}

		T& back()
		{
    
    
			return _head->_prev->_data;
		}

		const T& back()const
		{
    
    
			return _head->_prev->_data;
		}



		/// //
		/// 

		//增加删除部分
		void push_back(const T& val)
		{
    
    
			insert(end(), val);
		}

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

		iterator insert(iterator pos, const T& val)
		{
    
    
			Node* newnode = new Node(val);
			Node* cur = pos._node;
			Node* prev = cur->_prev;

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

			++_size;
			return newnode;
		}

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

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

		iterator erase(iterator pos)
		{
    
    
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;

			prev->_next = next;
			next->_prev = prev;
			delete cur;

			--_size;
			return next;
		}

		//获取有效数据量
		size_t size()
		{
    
    
			return _size;
		}

	private:
		Node* _head;  //这里存储卫兵节点,因为底层是双向循环链表,可以找到头和尾
		size_t _size; //只需要在insert和erase里面加减就可以
	};

}

Guess you like

Origin blog.csdn.net/2301_76269963/article/details/132437518