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?
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?
Risposte:
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 Comparator
che ordinerebbe gli elementi PriorityQueue
nell'ordine opposto al loro ordine naturale.
Collections.reverseOrder()
è anche sovraccarico per prendere un comparatore, quindi funziona anche se confronti oggetti personalizzati.
PriorityQueue(Comparator<? super E> comparator)
.
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.)
(x, y) -> y - x
potrebbe 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()
.
Puoi fornire un Comparator
oggetto 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!
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
può causare overflow
quindi dovrebbe evitare di usarlo e dovrebbe usarlo Collections.reverseOrder();
come comparatore o sostituire ba con il Integer.compare(a,b);
quale è stato aggiuntoJava 8
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));
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 ()
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
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());
Si può usare MinMaxPriorityQueue
(fa parte della libreria Guava):
ecco la documentazione . Invece di poll()
, devi chiamare il pollLast()
metodo.
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.
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;
}
});
if (rhs < lhs) return +1;
if (rhs> lhs) return -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.
PriorityQueue<Integer> lowers = new PriorityQueue<>((o1, o2) -> -1 * o1.compareTo(o2));
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.
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;
}
}