[C++] STL——list simulation implementation, constructor, iterator class implementation, operator overloading, addition, deletion, checking and modification

1. Simulate the realization of list

list use articles

insert image description here

1.1 Constructor

insert image description here

destructor

insert image description here

  When defining a class template list. We let this class template include an internal structure _list_node, which is used to represent the nodes of the linked list. The structure contains pointers to the previous node and the next node and the value of the node. The head node pointer of the linked list and the length of the linked list are saved in the list.

namespace my_list
{
    
    	
	//用类模板定义一个list结点
	template<class T>
	struct _list_node
	{
    
    
		//list结点的构造函数,T()作为缺省值,当未转参时调用
		_list_node(const T& val = T())
			:_next(nullptr)
			, _prev(nullptr)
			, _val(val)
		{
    
    }

		//list_node的成员函数,list为带头双向循环链表
		_list_node* _prev;
		_list_node* _next;
		T _val;
	};
	
	//用类模拟实现list
	template<class T>
	class list
	{
    
    
	private:
		typedef _list_node<T> Node;
		
	public:
		//list的构造函数,初始化头节点指针
		list()
		{
    
    
			_head = new Node;
			_head->_prev = _head;
			_head->_next = _head;

			_size = 0;
		}

		//析构函数
		~list()
		{
    
    
			iterator it = begin();
			while (it != end())
			{
    
    
				it = erase(it);
			}

			_size = 0;

			delete _head;
			_head = nullptr;
		}

	private:
		//成员函数为list的头节点指针,和链表长度
		Node* _head;
		size_t _size;
	};
}

1.2 Implementation of iterator class

insert image description here
insert image description here

  Because the underlying implementation of list is different from the previous vector and string, vector and string are arrays and sequence tables, while the underlying implementation of list is a linked list. For arrays and sequential tables, we can directly use pointers to implement their iterators, but for list types, we cannot use pointers to implement their iterators, because iterator ++ cannot access its next node. So here we create an iterator structure to encapsulate the node pointer to implement the exclusive iterator of the list

  This code defines an iterator structure named __list_iterator for traversing the linked list. The structure template has three template parameters: T represents the data type of the node in the linked list, Ref represents the reference type T&, Ptr represents the pointer type T * _node: a pointer to the node of the linked list. Constructor __list_iterator(Node* node): used to initialize the iterator object and assign the pointer node to _node. Various operator overloading can be achieved through _node.

  An iterator structure is defined for traversing and operating in the linked list. By overloading the operator, you can use the iterator object to access the elements in the linked list like a pointer.

//使用类进行封装Node*,来实现list的专属迭代器
//list迭代器和一些内置类型迭代器不一样,++无法准确访问到下一个位置
//typedef __list_iterator<T, T&> iterator;
//typedef __list_iterator<T, const T&> iterator;
template<class T, class Ref, class Ptr>
struct __list_iterator
{
    
    
	typedef _list_node<T> Node;
	typedef __list_iterator<T, Ref, Ptr> self;
	Node* _node;

	//迭代器的构造函数
	__list_iterator(Node* node)
		:_node(node)
	{
    
    }

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

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

	//重载前置++
	self& operator++()
	{
    
    
		_node = _node->_next;
		return *this;
	}

	//重载后置++
	self operator++(int)
	{
    
    
		__list_iterator<T> 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;
	}

	//重载!=
	bool operator!=(const self& it) const
	{
    
    
		return _node != it._node;
	}

	//重载==
	bool operator==(const self& it) const
	{
    
    
		return _node == it._node;
	}
};

  By creating a new structure to overload the iterator, we can implement the list-specific iterator to perform ++, - - operations on its linked list.

typedef __list_iterator<T, T&, T*> iterator;
typedef __list_iterator<T, const T&, const T*> const_iterator;

//list迭代器实现
iterator begin()
{
    
    
	//隐式类型转换,内置类型转换为自定义类型,实现迭代器功能
	//return _head->_next;
	return iterator(_head->_next);
}

iterator end()
{
    
    
	//return _head;
	return iterator(_head);
}

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

const_iterator end() const
{
    
    
	//return _head;
	return const_iterator(_head);
}

1.3 Operator overloading

  The operator overloading of iterators has been basically implemented in the above code.

insert image description here

  The assignment operator overload function operator= first creates a temporary linked list object lt, and assigns a copy of the incoming linked list object to lt. Then, call the swap function to exchange the current linked list object with the temporary linked list object. The reason for this is to implement exception-safe assignment operations. By assigning a copy of the incoming linked list object to a temporary linked list object, it is ensured that the incoming linked list object will not be affected during the swap. Finally, a reference to the current linked list object is returned.

  Through such implementation logic, the assignment operation between linked list objects can be realized, and it is guaranteed that the integrity of the data will not be destroyed when an exception occurs.

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

//赋值运算符重载
list<T>& operator=(list<T> lt)
	//list& operator=(list lt)
{
    
    
	swap(lt);

	return *this;
}

1.4 Add, delete, check and modify

push_back

insert image description here
  It is the same as the tail insertion of the leading doubly linked list. First, create a new linked list node newnode, whose value is the parameter x passed in. Then, get the tail pointer tail of the linked list, which is the previous node of the head node.

  Next, insert the new node newnode at the end of the linked list. First, point the predecessor pointer of the new node to the tail node, and point the successor pointer of the tail node to the new node. This connects the new node to the end of the linked list.

  Then, point the successor pointer of the new node to the head node, and point the predecessor pointer of the head node to the new node. This connects the new node to the head of the linked list.

//尾插
void push_back(const T& x)
{
    
    
	//创建一个新的链表结点,且获取到链表的尾指针
	Node* newnode = new Node(x);
	Node* tail = _head->_prev;

	//连接尾结点
	newnode->_prev = tail;
	tail->_next = newnode;

	//连接头节点
	_head->_prev = newnode;
	newnode->_next = _head;

	++_size;
}

insert

insert image description here

  Similar to the above logic.

//在pos位置之前插入
iterator insert(iterator pos, const T& x)
{
    
    
	Node* cur = pos._node;
	Node* prev = cur->_prev;
	Node* newnode = new Node(x);

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

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

	++_size;

	return newnode;
}

erase

insert image description here
  First, judge by asserting that the incoming iterator pos is not equal to the end iterator of the linked list. If it is equal to the end iterator, it means that the node to be deleted does not exist, which will cause an error. Then, get the node cur to be deleted according to the incoming iterator pos, as well as its predecessor node prev and successor node next.

  Then, the successor pointer of the predecessor node is pointed to the successor node, and the predecessor pointer of the successor node is pointed to the predecessor node. This disconnects the node to be deleted from the linked list. Then, free the memory of the node to be deleted. Also decrease the size of the linked list by 1.

  To avoid iterator invalidation, return a pointer to the next node as a new iterator. This ensures that after the node is deleted, the returned iterator can still be used for traversal and manipulation.

//删除
iterator erase(iterator pos)
{
    
    
	assert(pos != end());

	Node* cur = pos._node;
	Node* prev = cur->_prev;
	Node* next = cur->_next;

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

	delete cur;

	--_size;

	//为了避免迭代器失效,返回下一个结点指针
	return next;
}


fully realized

#pragma once

#include<assert.h>

namespace my_list
{
    
    	
	//用类模板定义一个list结点
	template<class T>
	struct _list_node
	{
    
    
		//list结点的构造函数,T()作为缺省值,当未转参时调用
		_list_node(const T& val = T())
			:_next(nullptr)
			, _prev(nullptr)
			, _val(val)
		{
    
    }

		//list_node的成员函数,list为带头双向循环链表
		_list_node* _prev;
		_list_node* _next;
		T _val;
	};

	//使用类进行封装Node*,来实现list的专属迭代器
	//list迭代器和一些内置类型迭代器不一样,++无法准确访问到下一个位置
	//typedef __list_iterator<T, T&> iterator;
	//typedef __list_iterator<T, const T&> iterator;
	template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
    
    
		typedef _list_node<T> Node;
		typedef __list_iterator<T, Ref, Ptr> self;
		Node* _node;

		//迭代器的构造函数
		__list_iterator(Node* node)
			:_node(node)
		{
    
    }

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

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

		//重载前置++
		self& operator++()
		{
    
    
			_node = _node->_next;
			return *this;
		}

		//重载后置++
		self operator++(int)
		{
    
    
			__list_iterator<T> 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;
		}

		//重载!=
		bool operator!=(const self& it) const
		{
    
    
			return _node != it._node;
		}

		//重载==
		bool operator==(const self& it) const
		{
    
    
			return _node == it._node;
		}
	};

	//实现const类型迭代器
	/*template<class T>
	struct __list_const_iterator
	{
		typedef list_node<T> Node;
		Node* _node;

		__list_const_iterator(Node* node)
			:_node(node)
		{}

		const T& operator*()
		{
			return _node->_val;
		}

		__list_const_iterator<T>& operator++()
		{
			_node = _node->_next;
			return *this;
		}

		__list_const_iterator<T> operator++(int)
		{
			__list_const_iterator<T> tmp(*this);

			_node = _node->_next;

			return tmp;
		}

		bool operator!=(const __list_const_iterator<T>& it)
		{
			return _node != it._node;
		}

		bool operator==(const __list_const_iterator<T>& it)
		{
			return _node == it._node;
		}
	};*/

	//用类模拟实现list
	template<class T>
	class list
	{
    
    
	private:
		typedef _list_node<T> Node;
		
	public:
		typedef __list_iterator<T, T&, T*> iterator;
		typedef __list_iterator<T, const T&, const T*> const_iterator;

		//list迭代器实现
		iterator begin()
		{
    
    
			//隐式类型转换,内置类型转换为自定义类型,实现迭代器功能
			//return _head->_next;
			return iterator(_head->_next);
		}

		iterator end()
		{
    
    
			//return _head;
			return iterator(_head);
		}

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

		const_iterator end() const
		{
    
    
			//return _head;
			return const_iterator(_head);
		}

		//初始化
		void empty_init()
		{
    
    
			_head = new Node;
			_head->_prev = _head;
			_head->_next = _head;

			_size = 0;
		}

		//list的构造函数,初始化头节点指针
		list()
		{
    
    
			empty_init();
		}

		//拷贝构造
		list(const list<T>& lt)
			//list(const list& lt)
		{
    
    
			empty_init();

			for (auto& e : lt)
			{
    
    
				push_back(e);
			}
		}

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

		//赋值运算符重载
		list<T>& operator=(list<T> lt)
			//list& operator=(list lt)
		{
    
    
			swap(lt);

			return *this;
		}

		//析构函数
		~list()
		{
    
    
			clear();

			delete _head;
			_head = nullptr;
		}

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

			_size = 0;
		}

		//尾插
		void push_back(const T& x)
		{
    
    
			//创建一个新的链表结点,且获取到链表的尾指针
			Node* newnode = new Node(x);
			Node* tail = _head->_prev;

			//连接尾结点
			newnode->_prev = tail;
			tail->_next = newnode;

			//连接头节点
			_head->_prev = newnode;
			newnode->_next = _head;

			++_size;

			//insert(end(), x);
		}

		//头插
		void push_front(const T& x)
		{
    
    
			insert(begin(), x);
		}

		//尾删
		void pop_back()
		{
    
    
			erase(--end());
		}

		//头删
		void pop_front()
		{
    
    
			erase(begin());
		}

		//在pos位置之前插入
		iterator insert(iterator pos, const T& x)
		{
    
    
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* newnode = new Node(x);

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

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

			++_size;

			return newnode;
		}

		//删除
		iterator erase(iterator pos)
		{
    
    
			assert(pos != end());

			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;

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

			delete cur;

			--_size;

			//为了避免迭代器失效,返回下一个结点指针
			return next;
		}

		//返回size
		size_t size()
		{
    
    
			/*size_t sz = 0;
			iterator it = begin();
			while (it != end())
			{
				++sz;
				++it;
			}

			return sz;*/

			return _size;
		}

	private:
		//成员函数为list的头节点指针,和链表长度
		Node* _head;
		size_t _size;
	};

	//打印函数
	void print(const list<int>& lt)
	{
    
    
		list<int>::const_iterator it = lt.begin();
		while (it != lt.end())
		{
    
    
			// (*it) += 1;
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}
}


test code

#define _CRT_SECURE_NO_WARNINGS 1

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

#include"list.h"

void test_list1()
{
    
    
	//list<int> lt;
	//lt.push_back(1);
	//lt.push_back(2);
	//lt.push_back(3);
	//lt.push_back(4);
	//for (auto e : lt)
	//{
    
    
	//	cout << e << " ";
	//}
	//cout << endl;

	my_list::list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	
	my_list::list<int>::iterator it = lt.begin();

	while (it != lt.end())
	{
    
    
		cout << *it << " ";
		++it;
	}
	cout << endl;

	auto itt = lt.begin();

	while (itt != lt.end())
	{
    
    
		++(*itt);
		++itt;
	}

	for (auto e: lt)
	{
    
    
		cout << e << " ";
	}
	cout << endl;
}

struct A
{
    
    
	A(int a1 = 0, int a2 = 0)
		:_a1(a1)
		, _a2(a2)
	{
    
    }

	int _a1;
	int _a2;
};

void test_list2()
{
    
    
	my_list::list<A> lt;
	lt.push_back(A(1, 1));
	lt.push_back(A(2, 2));
	lt.push_back(A(3, 3));
	lt.push_back(A(4, 4));

	auto it = lt.begin();
	while (it != lt.end())
	{
    
    
		//cout << *(it)._a1 << " " << *(it)._a2 <<endl;
		cout << it->_a1 << " " << it->_a2 << endl;
		++it;
	}
	cout << endl;
}

void test_list3()
{
    
    
	my_list::list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	for (auto e : lt)
	{
    
    
		cout << e << " ";
	}
	cout << endl;

	lt.push_front(5);
	lt.push_front(6);

	print(lt);

	lt.pop_front();
	lt.pop_back();

	print(lt);

	lt.clear();
	lt.push_back(10);
	lt.push_back(20);
	lt.push_back(30);
	lt.push_back(40);

	print(lt);

	cout << lt.size() << endl;
	
}


int main()
{
    
    
	//test_list1();
	//test_list2();
	test_list3();
	return 0;
}

Guess you like

Origin blog.csdn.net/Crocodile1006/article/details/132051594