Simulate the implementation of C of list++

Posted by redesigner on Fri, 12 Jun 2020 07:46:09 +0200

Simulation Implementation of list in C + +
Before simulating the implementation of list, we need to analyze list
1. The differences between list and other implementations such as vector
List is implemented by using the leading two-way circular list. One of the biggest differences between list and vector and string is the implementation of iterator.
2. Analysis of iterator
Iterators are similar to pointers. Why can we directly use a pointer to represent them in the implementation of vector and string, but not list?
Reason: list is implemented by a linked list, and its space is not necessarily continuous. Therefore, the implementation of iterator + + or - operation does not know which node it will point to at all. For the dereference of iterator, a linked list node cannot be dereferenced directly. In summary, a simple pointer cannot satisfy the implementation of iterator.
3. Implementation of iterator
To implement the iterator of list, we need to encapsulate the node, and then use operator overload to implement a list iterator. The specific code is as follows:

template<class T,class Ref,class Ptr>
struct Listiterator
{
	typedef ListNode<T> Node;
	typedef Listiterator<T,Ref,Ptr> self;
	Node *_node;
	Listiterator(Node *node)
		:_node(node)
	{}
	Ref& operator*()//Dereference of iterator
	{
		return _node->_value;
	}
	self& operator++()//Move to next node
	{
		_node = _node->_next;
		return *this;
	}
	self& operator--()//Move to previous node
	{
		_node = _node->_prev;
		return *this;
	}
	bool operator!=(const self& it)//Judge whether two nodes are equal
	{
		return _node != it._node;
	}
	Ptr operator->()//->Operator overload
	{
		return &_node->_value;
	}
};

As for the reason why we need to give three template parameters, it is because there are modifiable and non modifiable iterators in the iterator. After three template parameters, we can distinguish const iterator very well. In this way, we only need to implement the encapsulation of one iterator, otherwise we need to implement the encapsulation of two iterators. Although the underlying implementation is the same, the writing will be reduced Our workload.
4. Encapsulate a node

struct ListNode//Define a node
{
	T _value;
	ListNode<T> *_next;
	ListNode<T> *_prev;
	ListNode(const T&val=T())
		:_value(val)
		, _next(nullptr)
		, _prev(nullptr)
	{}
};

5. The complete code is as follows

#include<iostream>
using namespace std;
template<class T>
struct ListNode//Define a node
{
	T _value;
	ListNode<T> *_next;
	ListNode<T> *_prev;
	ListNode(const T&val=T())
		:_value(val)
		, _next(nullptr)
		, _prev(nullptr)
	{}
};

//Encapsulating nodes to construct an iterator
template<class T,class Ref,class Ptr>
struct Listiterator
{
	typedef ListNode<T> Node;
	typedef Listiterator<T,Ref,Ptr> self;
	Node *_node;
	Listiterator(Node *node)
		:_node(node)
	{}
	Ref& operator*()//Dereference of iterator
	{
		return _node->_value;
	}
	self& operator++()//Move to next node
	{
		_node = _node->_next;
		return *this;
	}
	self& operator--()//Move to previous node
	{
		_node = _node->_prev;
		return *this;
	}
	bool operator!=(const self& it)//Judge whether two nodes are equal
	{
		return _node != it._node;
	}
	Ptr operator->()//->Operator overload
	{
		return &_node->_value;
	}
};

//Two way circular list with head
template<class T>
class List
{
public:
	typedef Listiterator<T,T&,T*> iterator;
	typedef Listiterator<T, const T&, const T*> const_iterator;
	typedef ListNode<T> Node;
	List()//non-parameter constructor 
		:_header(new Node)
	{
		_header->_prev = _header->_next = _header;
	}
	void pushBack(const T& val)//Endinterpolate a value
	{
		Node *prev = _header->_prev;
		Node *newNode = new Node(val);
		prev->_next = newNode;
		newNode->_prev = prev;
		newNode->_next = _header;
		_header->_prev = newNode;
	}
	void insert(iterator pos, const T& val)//Insert a value anywhere
	{
		Node *prev = pos._node->_prev;
		Node *newNode = new Node(val);
		prev->_next = newNode;
		newNode->_prev = prev;
		newNode->_next = pos._node;
		pos._node->_prev = newNode;
	}
	void pushFront(const T& val)//Head insertion
	{
		insert(begin(), val);
	}
	void popFront()//Head deletion
	{
		erase(begin());
	}
	void popBack()//Censored
	{
		erase(--end());
	}
	iterator erase(iterator pos)//Delete anywhere
	{
		if (pos != end())
		{
			Node *prev = pos._node->_prev;
			Node *next = pos._node->_next;
			Node *curNode = pos._node;
			delete curNode;
			prev->_next = next;
			next->_prev = prev;
			return iterator(next);
		}
		return pos;
	}
	iterator begin()
	{
		return iterator(_header->_next);
	}
	iterator end()
	{
		return iterator(_header);
	}
	const_iterator cbegin() const
	{
		return const_iterator(_header->_next);
	}
	const_iterator cend() const
	{
		return const_iterator(_header);
	}
	void clear()
	{
		Node *start = _header->_next;
		while (start != _header)
		{
			Node *next = start->_next;
			delete start;
			start = next;
		}
	}
	~List()
	{
		if (_header)
		{
			clear();
			delete _header;
			_header = nullptr;
		}
	}
private:
	Node *_header;
};
void test()
{
	List<int> str1;
	str1.pushBack(1);
	str1.pushBack(2);
	str1.pushBack(3);
	str1.pushBack(4);
	str1.pushFront(10);
	str1.popFront();
	str1.popBack();
	List<int>::const_iterator cit = str1.cbegin();
	while (cit != str1.cend())
	{
		cout << *cit << " ";
		++cit;
	}
	cout << endl;
}
int main()
{
	test();
	system("pause");
	return 0;
}