Come posso ottenere un PriorityQueue
ordinamento su ciò che voglio che ordinino?
Come posso ottenere un PriorityQueue
ordinamento su ciò che voglio che ordinino?
Risposte:
Usa il sovraccarico del costruttore che accetta a Comparator<? super E> comparator
e passa un comparatore che confronta in modo appropriato per il tuo ordinamento. Se fornisci un esempio di come desideri ordinare, possiamo fornire del codice di esempio per implementare il comparatore se non sei sicuro. (È piuttosto semplice però.)
Come è stato detto altrove: offer
e add
sono solo diverse implementazioni del metodo di interfaccia. Nella fonte JDK che ho, add
chiamate offer
. Sebbene add
e offer
abbiano un comportamento potenzialmente diverso in generale a causa della capacità offer
di indicare che il valore non può essere aggiunto a causa di limiti di dimensione, questa differenza è irrilevante in PriorityQueue
cui è illimitato.
Ecco un esempio di ordinamento di una priorità prioritaria per lunghezza della stringa:
// Test.java
import java.util.Comparator;
import java.util.PriorityQueue;
public class Test {
public static void main(String[] args) {
Comparator<String> comparator = new StringLengthComparator();
PriorityQueue<String> queue = new PriorityQueue<String>(10, comparator);
queue.add("short");
queue.add("very long indeed");
queue.add("medium");
while (queue.size() != 0) {
System.out.println(queue.remove());
}
}
}
// StringLengthComparator.java
import java.util.Comparator;
public class StringLengthComparator implements Comparator<String> {
@Override
public int compare(String x, String y) {
// Assume neither string is null. Real code should
// probably be more robust
// You could also just return x.length() - y.length(),
// which would be more efficient.
if (x.length() < y.length()) {
return -1;
}
if (x.length() > y.length()) {
return 1;
}
return 0;
}
}
Ecco l'output:
corto
medio
molto a lungo
compare
implementazione non dovrebbe essere return x.length() - y.length()
? (Evita la previsione del ramo)
add()
per l'operazione di aggiunta, allora mi remove()
sento sensato; se stavo usando offer()
probabilmente userei poll()
... ma questa è solo una preferenza personale.
Possiamo usare lambda expression
o method reference
introdurre in Java 8. Nel caso in cui abbiamo archiviato alcuni valori String nella coda di priorità (con capacità 5) possiamo fornire un comparatore in linea (basato sulla lunghezza della stringa):
Usando l'espressione lambda
PriorityQueue<String> pq=
new PriorityQueue<String>(5,(a,b) -> a.length() - b.length());
Utilizzando il metodo di riferimento
PriorityQueue<String> pq=
new PriorityQueue<String>(5, Comparator.comparing(String::length));
Quindi possiamo usarne uno come:
public static void main(String[] args) {
PriorityQueue<String> pq=
new PriorityQueue<String>(5, (a,b) -> a.length() - b.length());
// or pq = new PriorityQueue<String>(5, Comparator.comparing(String::length));
pq.add("Apple");
pq.add("PineApple");
pq.add("Custard Apple");
while (pq.size() != 0)
{
System.out.println(pq.remove());
}
}
Questo stamperà:
Apple
PineApple
Custard Apple
Per invertire l'ordine (per cambiarlo nella coda con priorità massima) è sufficiente modificare l'ordine nel comparatore in linea o utilizzare reversed
come:
PriorityQueue<String> pq = new PriorityQueue<String>(5,
Comparator.comparing(String::length).reversed());
Possiamo anche usare Collections.reverseOrder
:
PriorityQueue<Integer> pqInt = new PriorityQueue<>(10, Collections.reverseOrder());
PriorityQueue<String> pq = new PriorityQueue<String>(5,
Collections.reverseOrder(Comparator.comparing(String::length))
Quindi possiamo vedere che Collections.reverseOrder
è sovraccarico per prendere un comparatore che può essere utile per oggetti personalizzati. Le reversed
utilizza in realtà Collections.reverseOrder
:
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
Come da doc
Il metodo di offerta inserisce un elemento, se possibile, altrimenti restituisce false. Ciò differisce dal metodo Collection.add, che può non riuscire ad aggiungere un elemento solo generando un'eccezione non selezionata. Il metodo di offerta è progettato per l'uso quando l'errore è un evento normale, piuttosto che eccezionale, ad esempio in code a capacità fissa (o "limitate").
Quando si utilizza una coda a capacità limitata, offer () è generalmente preferibile aggiungere (), che può non riuscire a inserire un elemento solo lanciando un'eccezione. E PriorityQueue è una coda di priorità illimitata basata su un heap di priorità.
5
indica la capacità iniziale della coda?
Basta passare appropriato Comparator
al costruttore :
PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
L'unica differenza tra offer
e add
è l'interfaccia a cui appartengono. offer
appartiene a Queue<E>
, mentre add
originariamente è visto Collection<E>
nell'interfaccia. A parte questo, entrambi i metodi fanno esattamente la stessa cosa: inserire l'elemento specificato nella coda di priorità.
da API coda :
Il metodo di offerta inserisce un elemento, se possibile, altrimenti restituisce false. Ciò differisce dal metodo Collection.add, che può non riuscire ad aggiungere un elemento solo generando un'eccezione non selezionata. Il metodo di offerta è progettato per l'uso quando l'errore è un evento normale, piuttosto che eccezionale, ad esempio in code a capacità fissa (o "limitate").
Solo per rispondere alla domanda add()
vs offer()
(dal momento che l'altro ha una risposta perfettamente imo, e questo potrebbe non essere):
Secondo JavaDoc sulla coda dell'interfaccia , "Il metodo di offerta inserisce un elemento, se possibile, altrimenti restituisce false. Ciò differisce dal metodo Collection.add, che può non riuscire ad aggiungere un elemento solo generando un'eccezione non selezionata. Il metodo di offerta è progettato per utilizzare quando l'errore è un'occorrenza normale, piuttosto che eccezionale, ad esempio in code a capacità fissa (o "limitate"). "
Ciò significa che se puoi aggiungere l'elemento (che dovrebbe sempre essere il caso in PriorityQueue), funzionano esattamente allo stesso modo. Ma se non riesci ad aggiungere l'elemento, offer()
ti darà un false
ritorno bello e carino , mentre add()
genera una brutta eccezione non controllata che non vuoi nel tuo codice. Se la mancata aggiunta indica che il codice funziona come previsto e / o è qualcosa che verifichi normalmente, utilizza offer()
. Se la mancata aggiunta indica che qualcosa non funziona, utilizzare add()
e gestire l'eccezione risultante generata in base alle specifiche dell'interfaccia Collection .
Entrambi sono implementati in questo modo per riempire il contratto sull'interfaccia Queue che specifica i offer()
fallimenti restituendo un false
( metodo preferito nelle code a capacità limitata ) e mantengono anche il contratto sull'interfaccia Collection che specifica add()
fallisce sempre lanciando un'eccezione .
Comunque, spero che chiarisca almeno quella parte della domanda.
Qui, possiamo definire un comparatore definito dall'utente:
Sotto il codice:
import java.util.*;
import java.util.Collections;
import java.util.Comparator;
class Checker implements Comparator<String>
{
public int compare(String str1, String str2)
{
if (str1.length() < str2.length()) return -1;
else return 1;
}
}
class Main
{
public static void main(String args[])
{
PriorityQueue<String> queue=new PriorityQueue<String>(5, new Checker());
queue.add("india");
queue.add("bangladesh");
queue.add("pakistan");
while (queue.size() != 0)
{
System.out.printf("%s\n",queue.remove());
}
}
}
Produzione :
india pakistan bangladesh
Differenza tra l'offerta e i metodi di aggiunta: link
Passalo a Comparator
. Inserisci il tipo desiderato al posto diT
Utilizzo di lambdas (Java 8+):
int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, (e1, e2) -> { return e1.compareTo(e2); });
Modo classico, usando una classe anonima:
int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, new Comparator<T> () {
@Override
public int compare(T e1, T e2) {
return e1.compareTo(e2);
}
});
Per ordinare in ordine inverso, basta scambiare e1, e2.
Mi chiedevo anche l'ordine di stampa. Considera questo caso, ad esempio:
Per una coda prioritaria:
PriorityQueue<String> pq3 = new PriorityQueue<String>();
Questo codice:
pq3.offer("a");
pq3.offer("A");
può stampare diversamente da:
String[] sa = {"a", "A"};
for(String s : sa)
pq3.offer(s);
Ho trovato la risposta da una discussione su un altro forum , in cui un utente ha detto, "i metodi offer () / add () inseriscono solo l'elemento nella coda. Se vuoi un ordine prevedibile, dovresti usare peek / poll che restituisce la testa della coda ".
In alternativa a utilizzare Comparator
, si può anche avere la classe che si sta utilizzando nel vostro PriorityQueue
implementareComparable
(e corrispondentemente l'override del compareTo
metodo).
Si noti che in genere è meglio usare Comparable
invece Comparator
che se quell'ordinamento è l'ordinamento intuitivo dell'oggetto - se, ad esempio, si dispone di un caso d'uso per ordinare gli Person
oggetti per età, probabilmente è meglio semplicemente utilizzare Comparator
invece.
import java.lang.Comparable;
import java.util.PriorityQueue;
class Test
{
public static void main(String[] args)
{
PriorityQueue<MyClass> queue = new PriorityQueue<MyClass>();
queue.add(new MyClass(2, "short"));
queue.add(new MyClass(2, "very long indeed"));
queue.add(new MyClass(1, "medium"));
queue.add(new MyClass(1, "very long indeed"));
queue.add(new MyClass(2, "medium"));
queue.add(new MyClass(1, "short"));
while (queue.size() != 0)
System.out.println(queue.remove());
}
}
class MyClass implements Comparable<MyClass>
{
int sortFirst;
String sortByLength;
public MyClass(int sortFirst, String sortByLength)
{
this.sortFirst = sortFirst;
this.sortByLength = sortByLength;
}
@Override
public int compareTo(MyClass other)
{
if (sortFirst != other.sortFirst)
return Integer.compare(sortFirst, other.sortFirst);
else
return Integer.compare(sortByLength.length(), other.sortByLength.length());
}
public String toString()
{
return sortFirst + ", " + sortByLength;
}
}
Produzione:
1, short
1, medium
1, very long indeed
2, short
2, medium
2, very long indeed
La coda di priorità ha una priorità assegnata a ciascun elemento, l'elemento con la priorità più alta appare nella parte superiore della coda. Ora, dipende da te come desideri assegnare la priorità a ciascuno degli elementi. In caso contrario, Java lo farà nel modo predefinito. All'elemento con il valore minimo viene assegnata la priorità più alta e quindi viene rimosso per primo dalla coda. Se ci sono più elementi con la stessa priorità massima, il pareggio viene interrotto arbitrariamente. Puoi anche specificare un ordine usando Comparator nel costruttore PriorityQueue(initialCapacity, comparator)
Codice di esempio:
PriorityQueue<String> queue1 = new PriorityQueue<>();
queue1.offer("Oklahoma");
queue1.offer("Indiana");
queue1.offer("Georgia");
queue1.offer("Texas");
System.out.println("Priority queue using Comparable:");
while (queue1.size() > 0) {
System.out.print(queue1.remove() + " ");
}
PriorityQueue<String> queue2 = new PriorityQueue(4, Collections.reverseOrder());
queue2.offer("Oklahoma");
queue2.offer("Indiana");
queue2.offer("Georgia");
queue2.offer("Texas");
System.out.println("\nPriority queue using Comparator:");
while (queue2.size() > 0) {
System.out.print(queue2.remove() + " ");
}
Produzione:
Priority queue using Comparable:
Georgia Indiana Oklahoma Texas
Priority queue using Comparator:
Texas Oklahoma Indiana Georgia
Altrimenti, puoi anche definire un comparatore personalizzato:
import java.util.Comparator;
public class StringLengthComparator implements Comparator<String>
{
@Override
public int compare(String x, String y)
{
//Your Own Logic
}
}
Ecco il semplice esempio che puoi usare per l'apprendimento iniziale:
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;
public class PQExample {
public static void main(String[] args) {
//PriorityQueue with Comparator
Queue<Customer> cpq = new PriorityQueue<>(7, idComp);
addToQueue(cpq);
pollFromQueue(cpq);
}
public static Comparator<Customer> idComp = new Comparator<Customer>(){
@Override
public int compare(Customer o1, Customer o2) {
return (int) (o1.getId() - o2.getId());
}
};
//utility method to add random data to Queue
private static void addToQueue(Queue<Customer> cq){
Random rand = new Random();
for(int i=0;i<7;i++){
int id = rand.nextInt(100);
cq.add(new Customer(id, "KV"+id));
}
}
private static void pollFromQueue(Queue<Customer> cq){
while(true){
Customer c = cq.poll();
if(c == null) break;
System.out.println("Customer Polled : "+c.getId() + " "+ c.getName());
}
}
}