[STL] Common usage of list and simulation implementation (complete source code attached)

Preface

In this article, we continue to learn about containers in STL. This article will explain lists.

1. Introduction and use of list

1.1 list introduction

listdocuments
Insert image description here
The underlying implementation of list is the headed two-way circular linked list learned from the data structure:
Insert image description here

1.2 List usage

Let’s take a look at some commonly used interfaces:

First, let’s take a look at the constructor:
Insert image description here
here are the ones we are familiar with, including the default constructor, n val constructor, iterator interval constructor and copy constructor.
Let’s take a look at iterators again:
Insert image description here
I believe the previous article has introduced iterators in detail so we won’t go into details here.

Let’s take a look at the modification operations:
Insert image description here

The difference between list, string and vector here is that
list does not have overloading [], which means that if we want to traverse and access the list, we can only use iterators.Iterators are the universal method. All containers can use iterators, but they []are only special methods for specific containers.

Traverse

int main()
{
    
    
    list<int> l;
    l.push_back(1);
    l.push_back(2);
    l.push_back(3);
    l.push_back(3);
    l.push_back(5);
    for (auto it = l.begin(); it != l.end(); ++it)
        cout << *it << " ";
    cout << endl;

    for (auto e : l)
        cout << e << " ";
    cout << endl;

    for (auto rit = l.rbegin(); rit != l.rend(); ++rit)
        cout << *rit << " ";
    cout << endl;
    return 0;
}

Insert image description here

Let's take a look at a few interfaces that have not been used much before:
Insert image description here
here splice, it can transfer part of the linked list to another linked list:
Insert image description here
removethat is, delete the specified element:
Insert image description here
mergeyou can merge two ordered linked lists:
Insert image description here

2. List simulation implementation

2.1 Classification of iterator functions

1. One-way iterator: only possible ++, not possible - -. For example, singly linked list, hash table;
2. Bidirectional iterator: ++both can be used --. For example, a doubly linked list;
3. Random access iterator: Yes ++ - -, it can also be +summed -. For example vector and string.
The iterator is a built-in type (inner class or defined in the class)

2.2 List iterator simulation implementation
2.2.1 Ordinary iterators

When simulating the implementation of string and vector, native pointers are used, and iterators are not encapsulated with classes. However, the STL standard library also encapsulates iterators with classes. When simulating the implementation of a list iterator, native pointers cannot be used because the node addresses of the list are discontinuous.

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

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

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

2.2.2 const iterator

Let’s take a look at the incorrect writing first:
在这里插入代码片typedef __list_iterator<T> iterator; const list<T>::iterator it=lt.begin();

In the STL library, this is achieved by giving one more parameter to the class template. In this way, the same class template can generate two different types of iterators.

template<class 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;


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

3. The difference between list and vector

vector list
underlying structure Dynamic sequence list, a continuous space Bidirectional circular linked list with head node
random access Supports random access, and the efficiency of accessing a certain element is O(1) Random access is not supported, and the efficiency of accessing an element is O(N)
Insertion and deletion Inserting and deleting at any position is inefficient and requires moving elements. The time complexity is O(N). Capacity expansion may be required during insertion. Capacity expansion: open up new space, copy elements, and release old space, resulting in lower efficiency. Insertion and deletion at any position is highly efficient, no need to move elements, and the time complexity is O(1)
Space utilization The bottom layer is continuous space, which is not easy to cause memory fragmentation, has high space utilization and high cache utilization. The underlying nodes are dynamically opened. Small nodes are prone to memory fragmentation, low space utilization, and low cache utilization.
Iterator Original ecological pointer Encapsulate the original ecological pointer
Iterator invalid When inserting elements, all iterators must be reassigned, because inserting elements may cause re-expansion, causing the original iterators to become invalid. When deleting, the current iterator needs to be reassigned, otherwise it will become invalid. Bidirectional circular linked list with head node
scenes to be used Need efficient storage, support random access, do not care about insertion and deletion efficiency Lots of insert and delete operations, don't care about random access

4. Source code

list.h

#include<iostream>
using namespace std;
namespace w
{
    
    
	template<class T>
	struct list_node
	{
    
    
		list_node<T>* _next;
		list_node<T>* _prev;
		T _val;

		list_node(const T& val = T())
			:_next(nullptr)
			, _prev(nullptr)
			, _val(val)
		{
    
    }
	};

	// typedef __list_iterator<T, T&, T*> iterator;
	// typedef __list_iterator<T, const T&, const T*> const_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)
		{
    
    
			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;
		}

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

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


	template<class 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;


		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()
		{
    
    
			empty_init();
		}

		// lt2(lt1)
		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)
		{
    
    
			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_t size()
		{
    
    
			return _size;
		}

	private:
		Node* _head;
		size_t _size;
	};

	void Print(const list<int>& lt)
	{
    
    
		list<int>::const_iterator it = lt.begin();
		while (it != lt.end())
		{
    
    
		
			cout << *it << " ";
			++it;
		}
		cout << endl;
	}

	
}

Guess you like

Origin blog.csdn.net/weixin_69423932/article/details/133484490