Tengo cola de prioridad en Java de Integers:
PriorityQueue<Integer> pq= new PriorityQueue<Integer>();
Cuando llamo pq.poll()
obtengo el elemento mínimo.
Pregunta: ¿cómo cambiar el código para obtener el elemento máximo?
Tengo cola de prioridad en Java de Integers:
PriorityQueue<Integer> pq= new PriorityQueue<Integer>();
Cuando llamo pq.poll()
obtengo el elemento mínimo.
Pregunta: ¿cómo cambiar el código para obtener el elemento máximo?
Respuestas:
¿Qué tal esto?
PriorityQueue<Integer> queue = new PriorityQueue<>(10, Collections.reverseOrder());
queue.offer(1);
queue.offer(2);
queue.offer(3);
//...
Integer val = null;
while( (val = queue.poll()) != null) {
System.out.println(val);
}
El Collections.reverseOrder()
proporciona un Comparator
que ordenaría los elementos en el PriorityQueue
orden opuesto a su orden natural en este caso.
Collections.reverseOrder()
también está sobrecargado para tomar un comparador, por lo que también funciona si compara objetos personalizados.
PriorityQueue(Comparator<? super E> comparator)
.
Puede usar la expresión lambda desde Java 8.
El siguiente código imprimirá 10, el más grande.
// There is overflow problem when using simple lambda as comparator, as pointed out by Фима Гирин.
// PriorityQueue<Integer> pq = new PriorityQueue<>((x, y) -> y - x);
PriorityQueue<Integer> pq =new PriorityQueue<>((x, y) -> Integer.compare(y, x));
pq.add(10);
pq.add(5);
System.out.println(pq.peek());
La función lambda tomará dos enteros como parámetros de entrada, los restará entre sí y devolverá el resultado aritmético. La función lambda implementa la interfaz funcional, Comparator<T>
. (Esto se usa en el lugar, a diferencia de una clase anónima o una implementación discreta).
(x, y) -> y - x
puede no ser apropiado para enteros largos debido al desbordamiento. Por ejemplo, los números y = Integer.MIN_VALUE y x = 5 dan como resultado un número positivo. Es mejor usar new PriorityQueue<>((x, y) -> Integer.compare(y, x))
. Sin embargo, la mejor solución la da @Edwin Dalorzo para usar Collections.reverseOrder()
.
Puede proporcionar un Comparator
objeto personalizado que clasifique los elementos en orden inverso:
PriorityQueue<Integer> pq = new PriorityQueue<Integer>(defaultSize, new Comparator<Integer>() {
public int compare(Integer lhs, Integer rhs) {
if (lhs < rhs) return +1;
if (lhs.equals(rhs)) return 0;
return -1;
}
});
Ahora, la cola de prioridad invertirá todas sus comparaciones, por lo que obtendrá el elemento máximo en lugar del elemento mínimo.
¡Espero que esto ayude!
if (rhs < lhs) return +1;
if (rhs > lhs) return -1;
if (lhs < rhs) return +1; if (lhs > rhs) return -1;
PriorityQueue<Integer> pq = new PriorityQueue<Integer> (
new Comparator<Integer> () {
public int compare(Integer a, Integer b) {
return b - a;
}
}
);
b-a
puede causar, overflow
por lo que debe evitar usarlo y debe usarlo Collections.reverseOrder();
como comparador o reemplazar ba con el Integer.compare(a,b);
que se ha agregado enJava 8
En Java 8+ puede crear una cola de prioridad máxima a través de uno de estos métodos:
Método 1:
PriorityQueue<Integer> maxPQ = new PriorityQueue<>(Collections.reverseOrder());
Método 2:
PriorityQueue<Integer> maxPQ = new PriorityQueue<>((a,b) -> b - a);
Método 3:
PriorityQueue<Integer> maxPQ = new PriorityQueue<>((a,b) -> b.compareTo(a));
Los elementos de la cola de prioridad se ordenan de acuerdo con su orden natural, o mediante un Comparador proporcionado en el momento de la construcción de la cola.
El comparador debe anular el método de comparación.
int compare(T o1, T o2)
El método de comparación predeterminado devuelve un entero negativo, cero o un entero positivo ya que el primer argumento es menor, igual o mayor que el segundo.
La PriorityQueue predeterminada proporcionada por Java es Min-Heap, si desea un montón máximo, el siguiente es el código
public class Sample {
public static void main(String[] args) {
PriorityQueue<Integer> q = new PriorityQueue<Integer>(new Comparator<Integer>() {
public int compare(Integer lhs, Integer rhs) {
if(lhs<rhs) return +1;
if(lhs>rhs) return -1;
return 0;
}
});
q.add(13);
q.add(4);q.add(14);q.add(-4);q.add(1);
while (!q.isEmpty()) {
System.out.println(q.poll());
}
}
}
Referencia: https://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html#comparator ()
Aquí hay una muestra de Max-Heap en Java:
PriorityQueue<Integer> pq1= new PriorityQueue<Integer>(10, new Comparator<Integer>() {
public int compare(Integer x, Integer y) {
if (x < y) return 1;
if (x > y) return -1;
return 0;
}
});
pq1.add(5);
pq1.add(10);
pq1.add(-1);
System.out.println("Peek: "+pq1.peek());
La salida será 10
Esto se puede lograr mediante el siguiente código en Java 8 que ha introducido un constructor que solo toma un comparador.
PriorityQueue<Integer> maxPriorityQ = new PriorityQueue<Integer>(Collections.reverseOrder());
Puede usar MinMaxPriorityQueue
(es parte de la biblioteca de Guava):
aquí está la documentación . En lugar de poll()
, debe llamar al pollLast()
método.
Cambiar PriorityQueue a MAX PriorityQueue Método 1: Cola pq = new PriorityQueue <> (Collections.reverseOrder ()); Método 2: Cola pq1 = new PriorityQueue <> ((a, b) -> b - a); Veamos algunos ejemplos:
public class Example1 {
public static void main(String[] args) {
List<Integer> ints = Arrays.asList(222, 555, 666, 333, 111, 888, 777, 444);
Queue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
pq.addAll(ints);
System.out.println("Priority Queue => " + pq);
System.out.println("Max element in the list => " + pq.peek());
System.out.println("......................");
// another way
Queue<Integer> pq1 = new PriorityQueue<>((a, b) -> b - a);
pq1.addAll(ints);
System.out.println("Priority Queue => " + pq1);
System.out.println("Max element in the list => " + pq1.peek());
/* OUTPUT
Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222]
Max element in the list => 888
......................
Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222]
Max element in the list => 888
*/
}
}
Tomemos una entrevista famosa Problema: K-ésimo elemento más grande en una matriz usando PriorityQueue
public class KthLargestElement_1{
public static void main(String[] args) {
List<Integer> ints = Arrays.asList(222, 555, 666, 333, 111, 888, 777, 444);
int k = 3;
Queue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
pq.addAll(ints);
System.out.println("Priority Queue => " + pq);
System.out.println("Max element in the list => " + pq.peek());
while (--k > 0) {
pq.poll();
} // while
System.out.println("Third largest => " + pq.peek());
/*
Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222]
Max element in the list => 888
Third largest => 666
*/
}
}
De otra manera :
public class KthLargestElement_2 {
public static void main(String[] args) {
List<Integer> ints = Arrays.asList(222, 555, 666, 333, 111, 888, 777, 444);
int k = 3;
Queue<Integer> pq1 = new PriorityQueue<>((a, b) -> b - a);
pq1.addAll(ints);
System.out.println("Priority Queue => " + pq1);
System.out.println("Max element in the list => " + pq1.peek());
while (--k > 0) {
pq1.poll();
} // while
System.out.println("Third largest => " + pq1.peek());
/*
Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222]
Max element in the list => 888
Third largest => 666
*/
}
}
Como podemos ver, ambos están dando el mismo resultado.
Acabo de ejecutar una simulación de Monte-Carlo en ambos comparadores en el tipo de pila doble min max y ambos obtuvieron el mismo resultado:
Estos son los comparadores máximos que he usado:
(A) Comparador integrado de colecciones
PriorityQueue<Integer> heapLow = new PriorityQueue<Integer>(Collections.reverseOrder());
(B) Comparador personalizado
PriorityQueue<Integer> heapLow = new PriorityQueue<Integer>(new Comparator<Integer>() {
int compare(Integer lhs, Integer rhs) {
if (rhs > lhs) return +1;
if (rhs < lhs) return -1;
return 0;
}
});
if (rhs < lhs) return +1;
si (rhs> lhs) return -1;
Puedes probar algo como:
PriorityQueue<Integer> pq = new PriorityQueue<>((x, y) -> -1 * Integer.compare(x, y));
Lo que funciona para cualquier otra función de comparación de base que pueda tener.
PriorityQueue<Integer> lowers = new PriorityQueue<>((o1, o2) -> -1 * o1.compareTo(o2));
Puede intentar empujar elementos con signo inverso. Por ejemplo: Sumar a = 2 & b = 5 y luego sondear b = 5.
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.add(-a);
pq.add(-b);
System.out.print(-pq.poll());
Una vez que haya sondeado al principio de la cola, invierta el signo para su uso. Esto imprimirá 5 (elemento más grande). Se puede utilizar en implementaciones ingenuas. Definitivamente no es una solución confiable. No lo recomiendo
Podemos hacer esto creando nuestra clase CustomComparator que implementa la interfaz Comparator y anulando su método de comparación. A continuación se muestra el código para el mismo:
import java.util.PriorityQueue;
import java.util.Comparator;
public class Main
{
public static void main(String[] args) {
PriorityQueue<Integer> nums = new PriorityQueue<>(new CustomComparator());
nums.offer(21);
nums.offer(1);
nums.offer(8);
nums.offer(2);
nums.offer(-4);
System.out.println(nums.peek());
}
}
class CustomComparator implements Comparator<Integer>{
@Override
public int compare(Integer n1, Integer n2){
int val = n1.compareTo(n2);
if(val > 0)
return -1;
else if(val < 0)
return 1;
else
return 0;
}
}