Cambiar prioridad de cola a máxima prioridad

124

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?

Borut Flis
fuente
4
Creo que deberías usar el constructor que recibe un comparador para eso. Utilice Collections.reverseOrder para obtener un comparador inverso.
Edwin Dalorzo
1
necesitas pasar un comparador. ver stackoverflow.com/questions/683041/…
DarthVader
Esto podría ayudar: tech693.blogspot.com/2018/09/…
Java Guru

Respuestas:

232

¿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 Comparatorque ordenaría los elementos en el PriorityQueueorden opuesto a su orden natural en este caso.

Edwin Dalorzo
fuente
14
Collections.reverseOrder()también está sobrecargado para tomar un comparador, por lo que también funciona si compara objetos personalizados.
oveja voladora
14
PriorityQueue de Java 8 tiene un nuevo constructor, que solo toma el comparador como argumento PriorityQueue(Comparator<? super E> comparator).
abhisheknirmal
75

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).

Guangtong Shen
fuente
función lambda, nombra sus parámetros de entrada xey y devuelve yx, que es básicamente lo que hace la clase int comparator, excepto que devuelve xy
Edi Bice
15
El comparador como (x, y) -> y - xpuede 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().
Фима Гирин
1
@ ФимаГирин Eso es cierto. -2147483648 - 1 se convierte en 2147483647
Guangtong Shen
27

Puede proporcionar un Comparatorobjeto 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!

templatetypedef
fuente
5
tal vez para una prioridad máxima q el lhs <rhs devuelve +1; lo que escribiste aquí es mínimo q después de mi prueba
sivi
Para la impresión inversa, es decir, si los elementos más altos deben imprimirse primero en una cola de prioridad, debería serif (rhs < lhs) return +1; if (rhs > lhs) return -1;
Tia
@Diksha Creo que el código que tengo es equivalente a lo que estás publicando. Acabo de usar la relación mayor que en lugar de menor que.
templatetypedef
4
en realidad, mi error ... quise decir que debería ser así:if (lhs < rhs) return +1; if (lhs > rhs) return -1;
Tia
1
@ShrikantPrabhu Buena captura, ¡ya está arreglada!
templatetypedef
14
PriorityQueue<Integer> pq = new PriorityQueue<Integer> (
  new Comparator<Integer> () {
    public int compare(Integer a, Integer b) {
       return b - a;
    }
  }
);
Varun Juneja
fuente
Cuál es el problema ?
CMedina
Esto es perfecto y hace exactamente lo que se pidió al convertir un montón mínimo en un montón máximo.
Kamran
2
el uso b-apuede causar, overflowpor 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
Yug Singh
10

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)); 
apadana
fuente
8

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 ()

rohan
fuente
4

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

Nobal
fuente
4

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());
Anshu Shekhar
fuente
3

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.

Proyecto Chthonic
fuente
3

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.

Soudipta Dutta
fuente
3

Esto se puede lograr usando

PriorityQueue<Integer> pq = new PriorityQueue<Integer>(Collections.reverseOrder());
Ajinkya_M
fuente
1

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;
    }
});
sivi
fuente
Para la impresión inversa, es decir, si los elementos más altos se van a imprimir primero en una cola de prioridad, debería ser if (rhs < lhs) return +1;si (rhs> lhs) return -1;
Tia
Puede editarlo si lo desea. No tengo tiempo para confirmar lo que escribiste. En mi configuración, lo que escribí era correcto
sivi
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.

Horia Coman
fuente
1
PriorityQueue<Integer> lowers = new PriorityQueue<>((o1, o2) -> -1 * o1.compareTo(o2));
Sumit Kumar Saha
fuente
0

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

striker28
fuente
0

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;
    }
}
Hardik Vagadia
fuente