C++: uso de listas e implementación de simulación

introducción a la lista

  1. La lista es una plantilla de clase y la creación de instancias de <tipo> es una clase específica .
  2. Una lista es un contenedor secuencial que se puede insertar y eliminar en cualquier posición .
  3. La capa inferior de la lista es una estructura de lista vinculada circular bidireccional . Cada elemento de la lista vinculada se almacena en un nodo independiente que no está relacionado entre sí, y el puntero apunta al elemento anterior y al siguiente elemento en la lista. nodo.
  4. En comparación con otros contenedores secuenciales, el mayor defecto de la lista es que no admite acceso aleatorio en ninguna posición . Por ejemplo, para acceder al sexto nodo, debe iterar desde un nodo conocido a este nodo.

Diagrama de lista doblemente enlazada:
Diagrama de lista doblemente enlazada



listaInterfaz común

1. Estructura

función Función
lista (tipo_tamaño n, tipo_valor constante y val = tipo_valor()) La lista construida contiene n nodos cuyo valor es val
lista() Construir una lista vacía
lista (lista constante y x) copiar construcción
lista (InputIterator primero, InputIterator último) Inicialización del rango de iteradores
(plantilla, rango de iteradores que se puede pasar a otros contenedores)

2. Iteradores

función Función
comenzar() más final() Obtenga el iterador/const_iterator de la primera posición de datos, obtenga el iterador/const_iterator de la siguiente posición de los últimos datos
rbegin() más render() Iterador inverso, obtiene el iterador inverso de la última posición de datos, obtiene el iterador inverso de la posición anterior de los primeros datos

3. Capacidad

función Función
tamaño() Obtener el número de datos válidos
vacío() Determine si está vacío (el tamaño es 0 está vacío, devuelve verdadero)

4. Acceder a los datos

función Función
frente() Obtener una referencia a los datos del nodo principal.
atrás() Devuelve una referencia a los datos del nodo de cola.

5. Agregar, eliminar, verificar y modificar

función Función
push_front
(valor constante tipo_tipo y valor)
valor de datos del encabezado
push_back
(tipo_valor constante y valor)
Valor de datos eliminados de cola
pop_front() eliminar cabeza
pop_back() eliminar cola
insertar (posición del iterador, valor constante tipo_tipo y val) Insertar un elemento con valor val en la posición posición
borrar (posición del iterador) Eliminar el elemento en la posición
intercambiar (lista y x) intercambiar dos listas
claro() Borrar datos válidos

6. Invalidación del iterador

       La invalidación de iteración significa que el nodo señalado por el iterador no es válido, es decir, el nodo se elimina. Debido a que la estructura subyacente de la lista es una lista enlazada circular de dos vías con el nodo principal, el iterador de la lista no se invalidará cuando se inserte en la lista. Solo se invalidará cuando se elimine, y solo el La iteración que apunte al nodo eliminado será invalidada. , otros iteradores no se ven afectados.

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



Implementación de simulación de lista

1. Implementación de iteradores.

      A diferencia del vector, el iterador de lista no es un puntero nativo , porque lo que el usuario necesita obtener son los datos en el nodo en lugar de todo el nodo, y encontrar el siguiente nodo no se puede hacer simplemente con el puntero ++, por lo que necesita para ser iterado El controlador se encapsula por separado en una clase y los requisitos se cumplen sobrecargando operadores como *.

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. Código completo

#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里面加减就可以
	};

}

Supongo que te gusta

Origin blog.csdn.net/2301_76269963/article/details/132437518
Recomendado
Clasificación