[STL]: Simulationsimplementierung der Liste

Freunde und Jungs, wir sehen uns wieder. In dieser Ausgabe erkläre ich euch die Simulationsumsetzung von list. Wenn es euch nach der Lektüre inspiriert, hinterlasst gerne eure Kommentare und ich wünsche euch, dass all eure Wünsche in Erfüllung gehen. !

Spalte C-Sprache:C-Sprache: Vom Anfänger zum Meister

Datenstrukturspalte:Datenstruktur

Personenhauptnummer:stackY,

C + + Version:C++

Linux-Version:Linux

Inhaltsverzeichnis

1. Grundstruktur

2. Weiterleitungsiterator

2.1 Nicht-konstante Iteratoren

2.2 const-Iterator

2.3 Verbesserung und Optimierung des Forward-Iterators

3. Ändern Sie die zugehörigen Schnittstellen

3.1 Einfügen, Löschen

3.2 Schwanzeinfügung, Kopfeinführung, Schwanzlöschung, Kopflöschung und Reinigung

4. Kopierkonstruktion, Zuweisungsüberlastung und Zerstörung

5. Vollständiger Code


1. Grundstruktur

Die unterste Ebene der Liste ist eigentlich eine verknüpfte Liste mit einer führenden bidirektionalen Schleife. Bevor Sie die Implementierung simulieren, können Sie sich also ansehen, wie sie in der Bibliothek implementiert ist:

namespace ywh
{
	//链表结构
	template<class T>
	struct list_node
	{
		T _data;                 //节点中的数据
		list_node<T>* _prev;    //指向前一个节点的指针
		list_node<T>* _next;    //指向后一个节点的指针

        //构造
		list_node(const T& x = T())
			:_data(x)
			, _prev(nullptr)
			, _next(nullptr)
		{}

	};

	//list结构
	template<class T>
	class list
	{
	public:
		typedef list_node<T> Node;
	public:
		
		//空初始化
		void empty_init()
		{
			_head = new Node;
			_head->_prev = _head;
			_head->_next = _next;
		}
		//构造
		list()
		{
			empty_init();
		}

	private:
		Node* _head;  //链表的头节点
		size_t _size; //节点个数
	};
}

2. Weiterleitungsiterator

Die Methode zur Verwendung von Iteratoren in der Phase der Verwendung von Listen ist dieselbe wie die von Zeichenfolgen und Vektoren zuvor. Wenn Sie jedoch die Struktur einer verknüpften Liste kennen, wissen Sie, dass Sie diese verwenden müssen, um auf den nächsten Knoten in einer verknüpften Liste zuzugreifen Der nächste Zeiger im Knoten zeigt auf den nächsten Knoten, und Sie müssen auf die darin enthaltenen Daten zugreifen. Sie müssen die darin enthaltenen Daten finden, und ++ und Dereferenzierung können nicht auf die Knoten der verknüpften Liste zugreifen, daher müssen Iteratoren verwendet werden gekapselt werden, plus Bedienerüberlastung auf der untersten Ebene.

Bei der Implementierung von Iteratoren müssen Sie auch Kapselung und Operatorüberladung verwenden. Die Operatorüberladung erfordert die Verwendung von Operatoren wie ++, --, !=, ==, *, ->. Iteratoren werden in konstante Iteratoren und nicht konstante Iteratoren unterteilt. Schauen wir uns zunächst die nicht konstante Iteratoren an:

2.1 Nicht-konstante Iteratoren

Die Implementierung von Iteratoren wird im Allgemeinen mithilfe von struct gekapselt:

namespace ljm
{
	//链表结构
	template<class T>
	struct list_node
	{
		T _data;                 //节点中的数据
		list_node<T>* _prev;    //指向前一个节点的指针
		list_node<T>* _next;    //指向后一个节点的指针

		//构造
		list_node(const T& x = T())
			:_data(x)
			, _prev(nullptr)
			, _next(nullptr)
		{}

	};

	//非const正向迭代器
	template<class T>
	struct __list_iterator
	{
		typedef list_node<T> Node;
		typedef __list_iterator<T> self;
		Node* _node;
		//迭代器构造
		__list_iterator(Node* node)
			:_node(node)
		{}
		
		//前置
		//operator++
		self& operator++()
		{
			return _node->_next;
		}
		//operator--
		self& operator--()
		{
			return _node->_prev;
		}

		//后置
		self operator++(int)
		{
			self* tmp(_node);
			_node = _node->_next;
			return tmp;
		}
		//operator--
		self operator--(int)
		{
			self* tmp(_node);
			_node = _node->_prev;
			return tmp;
		}

		//operator*
		T& operator*()
		{
			return _node->_data;
		}
		//operator->
		T* operator->()
		{
			return &_node->_data;
		}
		//operator!=
		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
		//operator==
		bool operator==(const self& s)
		{
			return _node == s._node;
		}
	};

	//list结构
	template<class T>
	class list
	{
	public:
		typedef list_node<T> Node;
	public:
		
		//空初始化
		void empty_init()
		{
			_head = new Node;
			_head->_prev = _head;
			_head->_next = _head;
		}
		//构造
		list()
		{
			empty_init();
		}
        ///正向迭代器
		iterator begin()
		{
			return iterator(_head->_next); //使用匿名对象进行构造
		}
		iterator end()
		{
			return iterator(_head);
		}

	private:
		Node* _head;  //链表的头节点
		size_t _size; //节点个数
	};
}

2.2 const-Iterator

Die am Iterator beteiligten Änderungen sind * und ->. Die Funktion des const-Iterators besteht darin, dass der Inhalt, auf den verwiesen wird, nicht geändert werden kann und er selbst nicht geändert werden kann, sodass er neu gekapselt werden muss:

namespace ljm
{
	//链表结构
	template<class T>
	struct list_node
	{
		T _data;                 //节点中的数据
		list_node<T>* _prev;    //指向前一个节点的指针
		list_node<T>* _next;    //指向后一个节点的指针

		//构造
		list_node(const T& x = T())
			:_data(x)
			, _prev(nullptr)
			, _next(nullptr)
		{}

	};

	//非const正向迭代器
	//...

	//const正向迭代器
	template<class T>
	struct __list_const_iterator
	{
		typedef list_node<T> Node;
		typedef __list_const_iterator<T> self;
		Node* _node;
		//迭代器构造
		__list_const_iterator(Node* node)
			:_node(node)
		{}

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

		//后置
		self operator++(int)
		{
			self* tmp(_node);
			_node = _node->_next;
			return tmp;
		}
		//operator--
		self operator--(int)
		{
			self* tmp(_node);
			_node = _node->_prev;
			return tmp;
		}

		//operator*
		const T& operator*()
		{
			return _node->_data;
		}
		//operator->
		const T* operator->()
		{
			return &_node->_data;
		}
		//operator!=
		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
		//operator==
		bool operator==(const self& s)
		{
			return _node == s._node;
		}
	};

	//list结构
	template<class T>
	class list
	{
	public:
		typedef list_node<T> Node;
		typedef __list_iterator<T> iterator;
		typedef __list_const_iterator<T> const_iterator;
	public:
		基本构造///
		//空初始化
		void empty_init()
		{
			_head = new Node;
			_head->_prev = _head;
			_head->_next = _head;
		}
		//构造
		list()
		{
			empty_init();
		}
		///正向迭代器
		iterator begin()
		{
			return iterator(_head->_next); //使用匿名对象进行构造
		}
		iterator end()
		{
			return iterator(_head);
		}
		const_iterator begin() const
		{
			return const_iterator(_head->_next);
		}
		const_iterator end() const
		{
			return const_iterator(_head);
		}

	private:
		Node* _head;  //链表的头节点
		size_t _size; //节点个数
	};
}

2.3 Verbesserung und Optimierung des Forward-Iterators

Aus den beiden oben genannten Schreibmethoden ist nicht schwer zu erkennen, dass viel Code wiederholt wird, was den Code sehr redundant macht. Wie können diese redundanten Codes zusammengeführt werden?

Wir können einen Blick darauf werfen, wie man es in der Bibliothek implementiert:

Mithilfe der generischen Programmierung und der Verwendung von Vorlagen wird diese Konvertierungsarbeit dem Compiler übergeben, und wir müssen nur konstante Parameter und nicht konstante Parameter übergeben:

namespace ywh
{
	//链表结构
	template<class T>
	struct list_node
	{
		T _data;                 //节点中的数据
		list_node<T>* _prev;    //指向前一个节点的指针
		list_node<T>* _next;    //指向后一个节点的指针

		//构造
		list_node(const T& x = T())
			:_data(x)
			, _prev(nullptr)
			, _next(nullptr)
		{}

	};

	//非const正向迭代器
	//   类型模板参数   传递引用      传递指针
	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)
		{}
		
		//前置
		//operator++
		self& operator++()
		{
			_node = _node->_next;
            return *this;
		}
		//operator--
		self& operator--()
		{
			_node = _node->_prev;
            return *this;
		}

		//后置
		self operator++(int)
		{
			self* tmp(_node);
			_node = _node->_next;
			return tmp;
		}
		//operator--
		self operator--(int)
		{
			self* tmp(_node);
			_node = _node->_prev;
			return tmp;
		}

		//operator*
		Ref operator*()
		{
			return _node->_data;
		}
		//operator->
		Ptr operator->()
		{
			return &_node->_data;
		}
		//operator!=
		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
		//operator==
		bool operator==(const self& s)
		{
			return _node == s._node;
		}
	};

	//list结构
	template<class T>
	class list
	{
	public:
		typedef list_node<T> Node;
		typedef __list_iterator<T, T&, T*> iterator;   //非const迭代器
		typedef __list_iterator<T, const T&, const T*> const_iterator;  //const迭代器
	public:
		基本构造///
		//空初始化
		void empty_init()
		{
			_head = new Node;
			_head->_prev = _head;
			_head->_next = _head;
		}
		//构造
		list()
		{
			empty_init();
		}
		///正向迭代器
		iterator begin()
		{
			return iterator(_head->_next); //使用匿名对象进行构造
		}
		iterator end()
		{
			return iterator(_head);
		}
		const_iterator begin() const
		{
			return const_iterator(_head->_next);
		}
		const_iterator end() const
		{
			return const_iterator(_head);
		}

	private:
		Node* _head;  //链表的头节点
		size_t _size; //节点个数
	};
}

3. Ändern Sie die zugehörigen Schnittstellen

3.1 Einfügen, Löschen

Das Einfügen und Löschen an der Pos-Position ist relativ einfach. Sie müssen den neuen Knoten verknüpfen und die Ausrichtung des Zeigers im Knoten ändern. Die Bibliothek verfügt über Rückgabewerte sowohl für das Einfügen als auch für das Löschen, daher werden wir auch den Rückgabewert hinzufügen bei der Umsetzung:

///修改相关接口
		//在pos位置插入节点
		iterator insert(iterator pos, const T& x)
		{
			//创建新新节点
			Node* newnode = new Node(x);
			//链接节点
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = cur;
			cur->_prev = newnode;
			//更新节点个数
			++_size;
			//返回新节点的位置
			return iterator(newnode);
		}
		//删掉pos位置的节点
		iterator erase(iterator pos)
		{
			//保存相对位置
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;
			//链接节点
			delete cur;
			prev->_next = next;
			next->_prev = prev;
			//更新节点个数
			--_size;
			//返回pos的下一个位置
			return iterator(next);
		}

Sie können sehen, dass der Iterator nach dem Einfügen nicht abläuft, die Pos-Position jedoch nach dem Löschen freigegeben wird, sodass der Iterator nach dem Löschen ungültig wird. Aktualisieren Sie den Iterator, bevor Sie ihn verwenden.

3.2 Schwanzeinfügung, Kopfeinführung, Schwanzlöschung, Kopflöschung und Reinigung

Nachdem Einfügen und Löschen implementiert wurden, können diese Schnittstellen direkt wiederverwendet werden:

        //尾插
		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());
		}
		//清理
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}

4. Kopierkonstruktion, Zuweisungsüberlastung und Zerstörung

Hier verwenden wir alle moderne Schrift:

 Die Kopierkonstruktion verwendet direkt Iteratoren, um sie zum Einfügen des Endes nacheinander zu durchlaufen.

//拷贝构造
		list(const list<T>& lt)
		{
			//先创建空节点
			empty_init();
			//依次尾插即可
			for (auto e : lt)
			{
				push_back(e);
			}
		}
		//operator=
		void swap(list<T>& lt)
		{
			std::swap(_head, lt._head);
			std::swap(_size, lt._size);
		}
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}
		//析构
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
			_size = 0;
		}

5. Vollständiger Code

 Header-Datei: List.h

#pragma once

namespace ywh
{
	//链表结构
	template<class T>
	struct list_node
	{
		T _data;                 //节点中的数据
		list_node<T>* _prev;    //指向前一个节点的指针
		list_node<T>* _next;    //指向后一个节点的指针

		//构造
		list_node(const T& x = T())
			:_data(x)
			, _prev(nullptr)
			, _next(nullptr)
		{}

	};

	//非const正向迭代器
	//   类型模板参数   传递引用      传递指针
	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)
		{}
		
		//前置
		//operator++
		self& operator++()
		{
			_node = _node->_next;
			return *this;
		}
		//operator--
		self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		//后置
		self operator++(int)
		{
			self* tmp(_node);
			_node = _node->_next;
			return tmp;
		}
		//operator--
		self operator--(int)
		{
			self* tmp(_node);
			_node = _node->_prev;
			return tmp;
		}

		//operator*
		Ref operator*()
		{
			return _node->_data;
		}
		//operator->
		Ptr operator->()
		{
			return &_node->_data;
		}
		//operator!=
		bool operator!=(const self& s)
		{
			return _node != s._node;
		}
		//operator==
		bool operator==(const self& s)
		{
			return _node == s._node;
		}
	};

	//list结构
	template<class T>
	class list
	{
	public:
		typedef list_node<T> Node;
		typedef __list_iterator<T, T&, T*> iterator;   //非const迭代器
		typedef __list_iterator<T, const T&, const T*> const_iterator;  //const迭代器
	public:
		基本构造///
		//空初始化
		void empty_init()
		{
			_head = new Node;
			_head->_prev = _head;
			_head->_next = _head;
		}
		//构造
		list()
		{
			empty_init();
		}
		//拷贝构造
		list(const list<T>& lt)
		{
			//先创建空节点
			empty_init();
			//依次尾插即可
			for (auto e : lt)
			{
				push_back(e);
			}
		}
		//operator=
		void swap(list<T>& lt)
		{
			std::swap(_head, lt._head);
			std::swap(_size, lt._size);
		}
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}
		//析构
		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
			_size = 0;
		}
		///正向迭代器
		iterator begin()
		{
			return iterator(_head->_next); //使用匿名对象进行构造
		}
		iterator end()
		{
			return iterator(_head);
		}
		const_iterator begin() const
		{
			return const_iterator(_head->_next);
		}
		const_iterator end() const
		{
			return const_iterator(_head);
		}
		///修改相关接口
		//在pos位置插入节点
		iterator insert(iterator pos, const T& x)
		{
			//创建新新节点
			Node* newnode = new Node(x);
			//链接节点
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = cur;
			cur->_prev = newnode;
			//更新节点个数
			++_size;
			//返回新节点的位置
			return iterator(newnode);
		}
		//删掉pos位置的节点
		iterator erase(iterator pos)
		{
			//保存相对位置
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;
			//链接节点
			delete cur;
			prev->_next = next;
			next->_prev = prev;
			//更新节点个数
			--_size;
			//返回pos的下一个位置
			return iterator(next);
		}
		//尾插
		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());
		}
		//清理
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}
		//节点个数
		size_t size()
		{
			return _size;
		}
	private:
		Node* _head;  //链表的头节点
		size_t _size; //节点个数
	};
}

Freunde und Jungs, gute Zeiten sind immer kurz. Unser Austausch in dieser Ausgabe endet hier. Wenn Sie wissen möchten, was als nächstes passiert, hören Sie sich bitte die nächste Folge an~. Vergessen Sie nicht, Sie nach dem Lesen wertzuschätzen. Vielen Dank dafür Ihre Unterstützung!  

Supongo que te gusta

Origin blog.csdn.net/Yikefore/article/details/134090437
Recomendado
Clasificación