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.