Cola de prioridad prioridad_queue y el uso de functores

cola de prioridad cola_prioridad

Cola de prioridad prioridad_queue es un adaptador de contenedor cuyo valor predeterminado es que el primer elemento sea el más grande entre los elementos que contiene de acuerdo con estrictos criterios de ordenamiento débiles.

La cola de prioridad utiliza el vector como contenedor subyacente para almacenar datos de forma predeterminada y utiliza el algoritmo de clasificación del montón para ordenar los datos en el vector, por lo que es priority_queueun montón. Nota: Priority_queue es grande de forma predeterminada.

priority_queueSe almacena <queue>en el archivo, para usarlo, solo necesita empaquetar queueel archivo.

Entonces, si necesitamos usar la ubicación del montón en el futuro, no necesitamos implementar un montón manualmente, simplemente podemos usarlo directamente priority_queue.

La siguiente es la definición de cola prioritaria:

template <class T, class Container = vector<T>,
  class Compare = less<typename Container::value_type> > class priority_queue;

El primer parámetro de plantilla es el tipo de elemento colocado en el contenedor del adaptador.
El segundo parámetro de plantilla es el adaptador, que por defecto es vector.
El tercer parámetro de plantilla es un functor, que por defecto es menos. Para garantizar que el valor predeterminado sea un gran montón

función Descripción de la interfaz
cola_prioridad() Construir una cola de prioridad vacía
prioridad_queue (InputIterator primero, InputIterator último) Construya una cola de prioridad utilizando el intervalo de iterador [primer, último)
vacío() Llámalo corto
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) Inserte el elemento x en la cola de prioridad
estallido() Eliminar el elemento más grande (más pequeño) en la cola de prioridad, es decir, el elemento superior del montón

Intentémoslo usando una cola prioritaria:

void test1()
{
    
    
	priority_queue<int> pq;
	pq.push(1);
	pq.push(6);
	pq.push(9);
	pq.push(3);
	pq.push(0);
	pq.push(2);

	while (!pq.empty())
	{
    
    
		cout << pq.top() << " ";
		pq.pop();
	}//输出 9 6 3 2 1 0 
	cout << endl;
}

Si primero implementamos un montón pequeño, solo necesitamos cambiar el tercer parámetro de plantilla, de modo que el tercer parámetro de plantilla sea. greater<T>Debido a que especificamos el tercer parámetro de plantilla, también necesitamos pasar manualmente el segundo parámetro de plantilla explícitamente.

A continuación implementamos un pequeño montón priority_queue:

void test1()
{
    
    
	priority_queue<int,vector<int>,greater<int>> pq;
	pq.push(1);
	pq.push(6);
	pq.push(9);
	pq.push(3);
	pq.push(0);
	pq.push(2);

	while (!pq.empty())
	{
    
    
		cout << pq.top() << " ";
		pq.pop();
	}//输出 0 1 2 3 6 9
	cout << endl;
}



Implementación de simulación de prioridad_queue

Debido a que la capa inferior de la cola de prioridad es la clasificación del montón, primero completamos el ajuste hacia abajo y hacia arriba en la clasificación del montón.

void AdjustDown(int parent)
{
    
    
	Compare com;
	size_t child = 2 * parent + 1;
	while (child < _con.size())
	{
    
    
		if (child + 1 < _con.size() && _con[child]<_con[child + 1])
		{
    
    
			child++;
		}

		if (_con[parent]< _con[child])
		{
    
    
			std::swap(_con[child], _con[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
    
    
			break;
		}
	}
}

void AdjustUp(int child)
{
    
    
	Compare com;

	int parent = (child - 1) / 2;
	while (parent >= 0)
	{
    
    
		if (_con[parent]< _con[child])
		{
    
    
			std::swap(_con[parent], _con[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
    
    
			break;
		}
	}

}

La función push primero inserta un elemento en el adaptador subyacente y luego llama al método de ajuste ascendente.

void push(const T& t)
{
    
    
	_con.push_back(t);
	AdjustUp(_con.size() - 1);

}

La función pop primero intercambia el primer elemento y el último elemento en el adaptador, luego elimina el último elemento y luego llama al método de ajuste descendente.

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

También hay varias funciones que son muy sencillas de implementar:

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

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

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

Código completo actual:

namespace my_priority_queue
{
    
    
	template<class T, class Container = std::vector<T>>
	class priority_queue
	{
    
    
	private:

		void AdjustDown(int parent)
		{
    
    
			size_t child = 2 * parent + 1;
			while (child < _con.size())
			{
    
    
				if (child + 1 < _con.size() && _con[child]<_con[child + 1])
				{
    
    
					child++;
				}

				if (_con[parent]< _con[child])
				{
    
    
					std::swap(_con[child], _con[parent]);
					parent = child;
					child = 2 * parent + 1;
				}
				else
				{
    
    
					break;
				}
			}
		}

		void AdjustUp(int child)
		{
    
    
			int parent = (child - 1) / 2;
			while (parent >= 0)
			{
    
    
				if (_con[parent]< _con[child])
				{
    
    
					std::swap(_con[parent], _con[child]);
					child = parent;
					parent = (child - 1) / 2;
				}
				else
				{
    
    
					break;
				}
			}
		}


	public:

		priority_queue()
		{
    
    }

		template<class InputIterator>
		priority_queue(InputIterator first, InputIterator last)
		{
    
    
			while (first != last)
			{
    
    
				_con.push_back(*first);
				first++;
			}

			for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
			{
    
    
				AdjustDown(i);
			}

		}

		void push(const T& t)
		{
    
    
			_con.push_back(t);
			AdjustUp(_con.size() - 1);

		}

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

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

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

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

	private:
		Container _con;
	};
}

Hasta ahora, hemos implementado una cola de prioridad de montón grande,
entonces, ¿cómo implementar una cola de prioridad de montón pequeña? Actualmente sólo podemos modificar las partes más pequeñas del ajuste hacia abajo y el ajuste hacia arriba:
inserte la descripción de la imagen aquí

En realidad, esto es bastante problemático: ¿hay alguna forma de cambiar entre las colas de prioridad del montón grande y el montón pequeño en segundos?
La respuesta es: puedes usar functores.



Funtor

Los functores también se llaman objetos de función. Los objetos de esta clase se pueden usar como funciones, haciendo que el uso de una clase parezca una función.
Su implementación es implementar una en la clase operator(). Con la sobrecarga de corchetes, los objetos de esta clase pueden ser Usar como una función

Aquí hay un funtor:

class IntLess
{
    
    
public:
	bool operator()(int x,int y)
	{
    
    
		return x < y;
	}

};

¿Cómo utilizar functores? Después de todo, un functor es una clase, por lo que cuando lo usamos, primero debemos crear una instancia de un objeto
y luego usar este objeto como una función ,
agregarlo después del objeto ()y pasar los parámetros según sea necesario.

void test2()
{
    
    
	IntLess LessFunc;
	cout<<LessFunc(1,2)<<endl;//仿函数的使用
}

LessFunc(1,2)será procesado en:LessFunc.operator()(1,2)

A continuación, utilice functores para mejorar la cola de prioridad de la implementación simulada.

template<class T>
struct Less//首字母大写,为了与库中的less区分
{
    
    
	bool operator()(const T& t1, const T& t2)
	{
    
    
		return t1 < t2;
	}
};


template<class T>
struct Greater
{
    
    
	bool operator()(const T& t1, const T& t2)
	{
    
    
		return t1 > t2;
	}
};

Primero, agregue un parámetro a la declaración de la plantilla:

template<class T,class Container = std::vector<T>,class Compare = Less<T>>

Luego, cambie la parte del juicio de tamaño del ajuste hacia arriba y el ajuste hacia abajo en funtores

void AdjustDown(int parent)
{
    
    
	Compare com;//仿函数使用前,实例化出一个对象
	size_t child = 2 * parent + 1;
	while (child < _con.size())
	{
    
    
		if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
		{
    
    
			child++;
		}

		if (com(_con[parent], _con[child]))
		{
    
    
			std::swap(_con[child], _con[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
    
    
			break;
		}
	}
}

void AdjustUp(int child)
{
    
    
	Compare com;//仿函数使用前,实例化出一个对象

	int parent = (child - 1) / 2;
	while (parent >= 0)
	{
    
    
		if (com(_con[parent], _con[child]))
		{
    
    
			std::swap(_con[parent], _con[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
    
    
			break;
		}
	}
	
}

Supongo que te gusta

Origin blog.csdn.net/weixin_64116522/article/details/132689495
Recomendado
Clasificación