[C++] Cola de prioridad y funtor

Tabla de contenido

1. Introducción y uso de la cola de prioridad

1. Introducción a la cola de prioridad

2. El uso de la cola de prioridad

En segundo lugar, el funtor

1. Escribir y usar funtores

Tres, implementación de simulación de prioridad_cola

4. Contenido extendido


1. Introducción y uso de la cola de prioridad

1. Introducción a la cola de prioridad

 1. Una cola de prioridad es un adaptador de contenedor cuyo primer elemento es siempre el más grande entre los elementos que contiene según criterios estrictos de clasificación débil.
 2. Este contexto es similar a un montón. Los elementos se pueden insertar en el montón en cualquier momento y solo se puede recuperar el elemento más grande del montón (el elemento superior en la cola de prioridad).
 3. La cola de prioridad se implementa como un adaptador de contenedor, que encapsula una clase de contenedor específica como su clase de contenedor subyacente, y la cola proporciona un conjunto de funciones miembro específicas para acceder a sus elementos. Los elementos se extraen de la "cola" de un contenedor en particular, que se denomina la parte superior de la cola de prioridad.
 4. El contenedor subyacente puede ser cualquier plantilla de clase de contenedor estándar o cualquier otra clase de contenedor especialmente diseñada. Los contenedores deben ser accesibles a través de iteradores de acceso aleatorio y admitir las siguientes operaciones:

  • vacío (): comprueba si el contenedor está vacío
  • size(): Devuelve el número de elementos válidos en el contenedor
  • front(): devuelve una referencia al primer elemento del contenedor
  • push_back(): inserta elementos al final del contenedor
  • pop_back(): elimina el elemento de cola del contenedor

 5. Las clases de contenedor estándar vector y deque cumplen estos requisitos. De forma predeterminada, se utiliza vector si no se especifica ninguna clase de contenedor para una instancia de clase de prioridad_cola en particular.
 6. Necesidad de admitir iteradores de acceso aleatorio para que la estructura del montón siempre se mantenga internamente. El adaptador de contenedor hace esto automáticamente llamando automáticamente a las funciones algorítmicas make_heap, push_heap y pop_heap cuando es necesario.

2. El uso de la cola de prioridad

 La cola de prioridad usa el vector como su contenedor de almacenamiento de datos subyacente de forma predeterminada, y el algoritmo de almacenamiento dinámico se usa en el vector para construir los elementos del vector en una estructura de almacenamiento dinámico, por lo que la cola_prioridad es un almacenamiento dinámico y todas las posiciones que necesitan usar el almacenamiento dinámico se puede considerar que utiliza la cola_prioridad. Nota: Priority_queue es un gran montón de forma predeterminada.

declaración de función Descripción de la interfaz
cola_de_prioridad()/cola_de_prioridad(primero,
último)
Construir una cola de prioridad vacía
vacío( ) Compruebe si la cola de prioridad está vacía, devuelva verdadero, de lo contrario, devuelva
falso
arriba( ) Devuelve el elemento más grande (el elemento más pequeño) en la cola de prioridad, es decir, el elemento superior del montón
empujar (x) Insertar el elemento x en la cola de prioridad
estallido() Elimine el elemento más grande (más pequeño) en la cola de prioridad, es decir, el elemento superior del montón

 Se puede ver que la prioridad_cola por defecto es un número más grande con mayor prioridad, es decir, por defecto es una pila grande.

 Si desea hacer la cola de prioridad, la prioridad pequeña es más alta, puede usar el funtor para lograrlo.

En segundo lugar, el funtor

El uso de funtores requiere incluir el archivo de encabezado  funcional .

Puede darse cuenta de que la prioridad más pequeña en la cola de prioridad es más alta. 

1. Escribir y usar funtores

Una característica de los funtores es que todos sobrecargan un operador "()" :

template <class T>
struct Less
{
	bool operator()(const T& x, const T& y)
	{
		return x < y;
	}
};

El método de uso es el siguiente:

 Mirando el uso de lessFunc , parece ser una función, pero de hecho es un objeto instanciado desde una clase. A esta clase la llamamos funtor, y los objetos funtor se pueden usar como funciones.

Tres, implementación de simulación de prioridad_cola

 La capa inferior de la cola de prioridad se implementa mediante un montón. Para obtener detalles sobre el montón, consulte el artículo "Montón: una estructura de árbol binario especial" .

El código específico es el siguiente:

namespace bin
{
	template <class T>
	struct less
	{
		bool operator()(const T& x, const T& y)
		{
			return x < y;
		}
	};

	template<class T>
	struct greater
	{
		bool operator()(const T& x, const T& y)
		{
			return x > y;
		}
	};

	template<class T, class Container = vector<T>, class Compare = less<T>>
	class priority_queue
	{
	public:
		void adjust_up(int child)
		{
			Compare com;
			int parent = (child - 1) / 2;
			while (child > 0)
			{
				//if (_con[parent] < _con[child])
				if (com(_con[parent], _con[child]))
				{
					swap(_con[child], _con[parent]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
					break;
				}
			}
		}

		void adjust_down(int parent)
		{
			int child = parent * 2 + 1;
			while (child < _con.size())
			{
				Compare com;
				//if (child + 1 < _con.size() && _con[child] < _con[child + 1])
				if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
				{
					++child;
				}
				//if (_con[parent] < _con[child])
				if (com(_con[parent], _con[child]))
				{
					swap(_con[child], _con[parent]);
					parent = child;
					child = parent * 2 + 1;
				}
				else
				{
					break;
				}
			}
		}

		void push(const T& x)
		{
			_con.push_back(x);
			adjust_up(_con.size() - 1);
		}

		void pop()
		{
			swap(_con[0], _con[_con.size() - 1]);
			_con.pop_back();
			adjust_down(0);
		}

		const T& top()
		{
			return _con[0];
		}

		size_t size()
		{
			return _con.size();
		}

		bool empty()
		{
			return _con.empty();
		}

	private:
		Container _con;
	};
}

El resultado de la prueba es correcto: 

4. Contenido extendido

Para el functor, podemos especificar libremente su método de comparación, como los siguientes escenarios:

class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
	bool operator<(const Date& d)const
	{
		return (_year < d._year) ||
			(_year == d._year && _month < d._month) ||
			(_year == d._year && _month == d._month && _day < d._day);
	}
	bool operator>(const Date& d)const
	{
		return (_year > d._year) ||
			(_year == d._year && _month > d._month) ||
			(_year == d._year && _month == d._month && _day > d._day);
	}
	friend ostream& operator<<(ostream& _cout, const Date& d)
	{
		_cout << d._year << "-" << d._month << "-" << d._day;
		return _cout;
	}
private:
	int _year;
	int _month;
	int _day;
};

class PDataLess
{
public:
	bool operator()(const Date* p1, const Date* p2)
	{
		return *p1 < *p2;
	}
};

class PDataGreater
{
public:
	bool operator()(const Date* p1, const Date* p2)
	{
		return *p1 > *p2;
	}
};

void TestPriorityQueue()
{
	priority_queue<Date*, vector<Date*>, PDataGreater> q;
	q.push(new Date(2023, 4, 8));
	q.push(new Date(2023, 4, 9));
	q.push(new Date(2023, 4, 7));
	cout << q.top() << endl;
}

 El tipo de variable miembro de la cola de prioridad que configuramos es un tipo de puntero, pero esperamos que su esquema de comparación sea comparar sus datos desreferenciados, lo que se puede lograr configurando la estrategia de comparación en el funtor:


 Eso es todo por el contenido de la cola de prioridad. Espero que me apoyen mucho. Si hay algo mal, por favor corríjanme, ¡gracias!

Supongo que te gusta

Origin blog.csdn.net/weixin_74078718/article/details/130017530
Recomendado
Clasificación