Cambia priorityQueue in max priorityqueue


125

Ho la coda di priorità in Java di Integers:

 PriorityQueue<Integer> pq= new PriorityQueue<Integer>();

Quando chiamo pq.poll()ottengo l'elemento minimo.

Domanda: come modificare il codice per ottenere l'elemento massimo?


5
Penso che dovresti usare il costruttore che riceve un comparatore per questo. Utilizza Collections.reverseOrder per ottenere un confronto invertito.
Edwin Dalorzo

1
devi passare un comparatore. vedi stackoverflow.com/questions/683041/...
DarthVader

Questo potrebbe aiutare: tech693.blogspot.com/2018/09/…
Java Guru

Risposte:


233

Che ne dici di questo:

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

In questo caso, Collections.reverseOrder()fornisce un Comparatorche ordinerebbe gli elementi PriorityQueuenell'ordine opposto al loro ordine naturale.


14
Collections.reverseOrder()è anche sovraccarico per prendere un comparatore, quindi funziona anche se confronti oggetti personalizzati.
pecore volanti il

14
PriorityQueue di Java 8 ha un nuovo costruttore, che prende solo il comparatore come argomento PriorityQueue(Comparator<? super E> comparator).
abhisheknirmal

75

Puoi usare l'espressione lambda da Java 8.

Il codice seguente stamperà 10, il più 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 funzione lambda prenderà due numeri interi come parametri di input, li sottrarrà l'uno dall'altro e restituirà il risultato aritmetico. La funzione lambda implementa l'interfaccia funzionale, Comparator<T>. (Viene utilizzato sul posto, al contrario di una classe anonima o di un'implementazione discreta.)


funzione lambda, nomina i suoi parametri di input xey e restituisce yx, che è fondamentalmente ciò che fa la classe comparator int tranne che restituisce xy
Edi Bice

15
Il tipo di comparatore (x, y) -> y - xpotrebbe non essere appropriato per interi lunghi a causa dell'overflow. Ad esempio, i numeri y = Integer.MIN_VALUE ex = 5 restituiscono un numero positivo. È meglio usare new PriorityQueue<>((x, y) -> Integer.compare(y, x)). Tuttavia, la soluzione migliore è data da @Edwin Dalorzo da usare Collections.reverseOrder().
Фима Гирин

1
@ ФимаГирин È vero. -2147483648 - 1 diventa 2147483647
Guangtong Shen

27

Puoi fornire un Comparatoroggetto personalizzato che classifica gli elementi nell'ordine 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;
    }
});

Ora, la coda di priorità invertirà tutti i suoi confronti, quindi otterrai l'elemento massimo anziché l'elemento minimo.

Spero che questo ti aiuti!


5
forse per una massima priorità q lhs <rhs torna +1; quello che hai scritto qui è minimo q dopo i miei test
sivi

Per la stampa inversa, ovvero se gli elementi più alti devono essere stampati per primi in una coda di priorità, dovrebbe essereif (rhs < lhs) return +1; if (rhs > lhs) return -1;
Tia

@Diksha credo che il codice che ho è equivalente a quello che stai pubblicando. Ho appena usato la relazione maggiore di piuttosto che minore di.
templatetypedef

4
in realtà, il mio errore .. Volevo dire che dovrebbe essere così:if (lhs < rhs) return +1; if (lhs > rhs) return -1;
Tia

1
@ShrikantPrabhu Buona presa - ora è stato risolto!
templatetypedef

14
PriorityQueue<Integer> pq = new PriorityQueue<Integer> (
  new Comparator<Integer> () {
    public int compare(Integer a, Integer b) {
       return b - a;
    }
  }
);

Qual è il problema ?
CMedina

Questo è perfetto e fa esattamente ciò che è stato richiesto trasformando un heap minimo in un heap massimo.
Kamran

2
l'utilizzo b-apuò causare overflowquindi dovrebbe evitare di usarlo e dovrebbe usarlo Collections.reverseOrder();come comparatore o sostituire ba con il Integer.compare(a,b);quale è stato aggiuntoJava 8
Yug Singh

10

In Java 8+ puoi creare una coda con priorità massima tramite uno di questi metodi:

Metodo 1:

PriorityQueue<Integer> maxPQ = new PriorityQueue<>(Collections.reverseOrder()); 

Metodo 2:

PriorityQueue<Integer> maxPQ = new PriorityQueue<>((a,b) -> b - a); 

Metodo 3:

PriorityQueue<Integer> maxPQ = new PriorityQueue<>((a,b) -> b.compareTo(a)); 

8

Gli elementi della coda di priorità vengono ordinati in base al loro ordinamento naturale o da un Comparatore fornito al momento della costruzione della coda.

Il comparatore dovrebbe sostituire il metodo di confronto.

int compare(T o1, T o2)

Il metodo di confronto predefinito restituisce un numero intero negativo, zero o un numero intero positivo poiché il primo argomento è minore, uguale o maggiore del secondo.

La PriorityQueue predefinita fornita da Java è Min-Heap, se si desidera un heap massimo, seguire è il codice

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

}

Riferimento: https://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html#comparator ()


4

Ecco un esempio di Max-Heap in 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());

L'output sarà 10


4

Ciò può essere ottenuto dal codice seguente in Java 8 che ha introdotto un costruttore che accetta solo un comparatore.

PriorityQueue<Integer> maxPriorityQ = new PriorityQueue<Integer>(Collections.reverseOrder());


3

Modificare PriorityQueue in MAX PriorityQueue Metodo 1: Queue pq = new PriorityQueue <> (Collections.reverseOrder ()); Metodo 2: Queue pq1 = new PriorityQueue <> ((a, b) -> b - a); Diamo un'occhiata ad alcuni esempi:

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

         */


    }
}

Facciamo una famosa intervista Problema: Kth Largest Element in an Array using 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

 */
    }
}

Un altro modo :

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

         */
    }
}

Come possiamo vedere, entrambi stanno dando lo stesso risultato.


3

Ciò può essere ottenuto utilizzando

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

1

Ho appena eseguito una simulazione Monte-Carlo su entrambi i comparatori su double heap sort min max ed entrambi sono arrivati ​​allo stesso risultato:

Questi sono i massimi comparatori che ho usato:

(A) Comparatore integrato delle collezioni

 PriorityQueue<Integer> heapLow = new PriorityQueue<Integer>(Collections.reverseOrder());

(B) Comparatore personalizzato

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

Per la stampa inversa, cioè se gli elementi più alti devono essere stampati per primi in una coda di priorità, dovrebbe essere if (rhs < lhs) return +1;if (rhs> lhs) return -1;
Tia

Puoi modificarlo se lo desideri. Non ho tempo per confermare quello che hai scritto. Nella mia configurazione quello che ho scritto era corretto
sivi

1

Puoi provare qualcosa come:

PriorityQueue<Integer> pq = new PriorityQueue<>((x, y) -> -1 * Integer.compare(x, y));

Che funziona per qualsiasi altra funzione di confronto di base che potresti avere.


1
PriorityQueue<Integer> lowers = new PriorityQueue<>((o1, o2) -> -1 * o1.compareTo(o2));

0

Puoi provare a spingere gli elementi con il segno inverso. Ad esempio: per aggiungere a = 2 & b = 5 e poi sondare b = 5.

PriorityQueue<Integer>  pq = new PriorityQueue<>();
pq.add(-a);
pq.add(-b);
System.out.print(-pq.poll());

Dopo aver interrogato la testa della coda, inverti il ​​segno per il tuo utilizzo. Questo stamperà 5 (elemento più grande). Può essere utilizzato in implementazioni ingenue. Sicuramente non una soluzione affidabile. Non lo consiglio.


0

Possiamo farlo creando la nostra classe CustomComparator che implementa l'interfaccia di Comparator e sovrascrivendo il suo metodo di confronto. Di seguito è riportato il codice per lo stesso:

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;
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.