Wie kann ich PriorityQueue
sortieren, wonach es sortiert werden soll?
Gibt es auch einen Unterschied zwischen den Methoden offer
und add
?
Wie kann ich PriorityQueue
sortieren, wonach es sortiert werden soll?
Gibt es auch einen Unterschied zwischen den Methoden offer
und add
?
Antworten:
Verwenden Sie die Konstruktorüberladung, die a benötigt, Comparator<? super E> comparator
und übergeben Sie einen Komparator, der auf die für Ihre Sortierreihenfolge geeignete Weise vergleicht. Wenn Sie ein Beispiel für die Sortierung angeben, können wir einen Beispielcode zur Implementierung des Komparators bereitstellen, wenn Sie sich nicht sicher sind. (Es ist allerdings ziemlich einfach.)
Wie bereits an anderer Stelle gesagt: offer
und add
sind nur verschiedene Implementierungen von Schnittstellenmethoden. In der JDK-Quelle habe ich add
Anrufe offer
. Obwohl add
und offer
hat möglicherweise für eine anderes Verhalten im Allgemeinen aufgrund der Fähigkeit , offer
um anzuzeigen , dass der Wert nicht aufgrund von Größenbeschränkungen hinzugefügt wird, ist dieser Unterschied unerheblich in PriorityQueue
welcher unbeschränkt ist.
Hier ist ein Beispiel für eine Prioritätswarteschlange, die nach Zeichenfolgenlänge sortiert ist:
// 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;
}
}
Hier ist die Ausgabe:
kurz
Mittel
sehr lange in der Tat
compare
Implementierung nicht einfach sein return x.length() - y.length()
? (Vermeidet Verzweigungsvorhersage)
add()
für den Addiervorgang verwenden, dann remove()
fühlt es sich vernünftig an; Wenn ich verwenden offer()
würde, würde ich wahrscheinlich verwenden poll()
... aber das ist nur eine persönliche Präferenz.
Wir können Java 8 verwenden lambda expression
oder method reference
in Java 8 einführen. Falls einige String-Werte in der Prioritätswarteschlange gespeichert sind (mit Kapazität 5), können wir einen Inline-Komparator (basierend auf der Länge des Strings) bereitstellen:
Verwenden des Lambda-Ausdrucks
PriorityQueue<String> pq=
new PriorityQueue<String>(5,(a,b) -> a.length() - b.length());
Verwenden der Methodenreferenz
PriorityQueue<String> pq=
new PriorityQueue<String>(5, Comparator.comparing(String::length));
Dann können wir jeden von ihnen verwenden als:
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());
}
}
Dies wird gedruckt:
Apple
PineApple
Custard Apple
Um die Reihenfolge umzukehren (um sie in die Warteschlange mit maximaler Priorität zu ändern), ändern Sie einfach die Reihenfolge im Inline-Komparator oder verwenden Sie sie reversed
als:
PriorityQueue<String> pq = new PriorityQueue<String>(5,
Comparator.comparing(String::length).reversed());
Wir können auch verwenden Collections.reverseOrder
:
PriorityQueue<Integer> pqInt = new PriorityQueue<>(10, Collections.reverseOrder());
PriorityQueue<String> pq = new PriorityQueue<String>(5,
Collections.reverseOrder(Comparator.comparing(String::length))
Wir können also sehen, dass dies Collections.reverseOrder
überladen ist, um einen Komparator zu verwenden, der für benutzerdefinierte Objekte nützlich sein kann. Das verwendet reversed
tatsächlich Collections.reverseOrder
:
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
Gemäß dem Dokument
Die Angebotsmethode fügt nach Möglichkeit ein Element ein, andernfalls wird false zurückgegeben. Dies unterscheidet sich von der Collection.add-Methode, bei der ein Element möglicherweise nur durch Auslösen einer nicht aktivierten Ausnahme nicht hinzugefügt werden kann. Die Angebotsmethode ist für die Verwendung konzipiert, wenn ein Fehler eher normal als außergewöhnlich ist, z. B. in Warteschlangen mit fester Kapazität (oder "begrenzt").
Wenn Sie eine Warteschlange mit eingeschränkter Kapazität verwenden, ist Offer () im Allgemeinen Add () vorzuziehen, wodurch ein Element möglicherweise nur durch Auslösen einer Ausnahme nicht eingefügt werden kann. Und PriorityQueue ist eine unbegrenzte Prioritätswarteschlange, die auf einem Prioritätsheap basiert.
5
dass die Startkapazität der Warteschlange angibt?
Übergeben Sie es einfach Comparator
an den Konstruktor :
PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
Der einzige Unterschied zwischen offer
und add
ist die Schnittstelle, zu der sie gehören. offer
gehört zu Queue<E>
, während add
ursprünglich in der Collection<E>
Schnittstelle gesehen wird. Abgesehen davon machen beide Methoden genau dasselbe - fügen Sie das angegebene Element in die Prioritätswarteschlange ein.
von der Warteschlangen-API :
Die Angebotsmethode fügt nach Möglichkeit ein Element ein, andernfalls wird false zurückgegeben. Dies unterscheidet sich von der Collection.add-Methode, bei der ein Element möglicherweise nur durch Auslösen einer nicht aktivierten Ausnahme nicht hinzugefügt werden kann. Die Angebotsmethode ist für die Verwendung konzipiert, wenn ein Fehler eher normal als außergewöhnlich ist, z. B. in Warteschlangen mit fester Kapazität (oder "begrenzt").
Nur um die add()
vs- offer()
Frage zu beantworten (da die andere imo perfekt beantwortet ist und dies möglicherweise nicht der Fall ist):
Laut JavaDoc in der Schnittstellenwarteschlange "fügt die Angebotsmethode nach Möglichkeit ein Element ein und gibt andernfalls false zurück. Dies unterscheidet sich von der Collection.add-Methode, bei der ein Element möglicherweise nur durch Auslösen einer nicht aktivierten Ausnahme nicht hinzugefügt werden kann. Die Angebotsmethode ist für ausgelegt Verwendung, wenn ein Fehler eher normal als außergewöhnlich ist, z. B. in Warteschlangen mit fester Kapazität (oder "begrenzten"). "
Das heißt, wenn Sie das Element hinzufügen können (was in einer PriorityQueue immer der Fall sein sollte), funktionieren sie genau gleich. Wenn Sie das Element jedoch nicht hinzufügen offer()
können, erhalten Sie eine schöne und hübsche false
Rendite, während Sie add()
eine böse, nicht aktivierte Ausnahme auslösen, die Sie nicht in Ihrem Code haben möchten. Wenn das Hinzufügen von Code nicht wie vorgesehen funktioniert und / oder normalerweise überprüft wird, verwenden Sie offer()
. Wenn das Hinzufügen nicht dazu führt, dass etwas nicht funktioniert, verwenden add()
und behandeln Sie die resultierende Ausnahme, die gemäß den Spezifikationen der Collection-Schnittstelle ausgelöst wird .
Sie werden beide auf diese Weise implementiert, um den Vertrag auf der Warteschlangenschnittstelle, die Fehler angibt offer()
, durch Rückgabe einer false
( in Warteschlangen mit eingeschränkter Kapazität bevorzugten Methode ) zu erfüllen und den Vertrag auf der Sammlungsschnittstelle, die angibt, add()
immer fehlzuschlagen, indem eine Ausnahme ausgelöst wird .
Wie auch immer, ich hoffe, das klärt zumindest diesen Teil der Frage.
Hier können wir einen benutzerdefinierten Komparator definieren:
Unter Code:
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());
}
}
}
Ausgabe :
india pakistan bangladesh
Unterschied zwischen Angebot und Hinzufügungsmethode: Link
Übergeben Sie es a Comparator
. Geben Sie anstelle von den gewünschten Typ einT
Verwenden von Lambdas (Java 8+):
int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, (e1, e2) -> { return e1.compareTo(e2); });
Klassische Methode mit anonymer Klasse:
int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, new Comparator<T> () {
@Override
public int compare(T e1, T e2) {
return e1.compareTo(e2);
}
});
Um in umgekehrter Reihenfolge zu sortieren, tauschen Sie einfach e1, e2 aus.
Ich habe mich auch über die Druckreihenfolge gewundert. Betrachten Sie diesen Fall zum Beispiel:
Für eine Prioritätswarteschlange:
PriorityQueue<String> pq3 = new PriorityQueue<String>();
Dieser Code:
pq3.offer("a");
pq3.offer("A");
kann anders drucken als:
String[] sa = {"a", "A"};
for(String s : sa)
pq3.offer(s);
Ich habe die Antwort aus einer Diskussion in einem anderen Forum gefunden , in der ein Benutzer sagte: "Die Methode quote () / add () fügt das Element nur in die Warteschlange ein. Wenn Sie eine vorhersehbare Reihenfolge wünschen, sollten Sie peek / poll verwenden, die den Kopf zurückgeben der Warteschlange. "
Alternativ zur Verwendung Comparator
können Sie auch die Klasse verwenden, die Sie in Ihrem PriorityQueue
Implementierungsprogramm verwendenComparable
(und die compareTo
Methode entsprechend überschreiben ).
Beachten Sie, dass es im Allgemeinen am besten ist, nur zu verwenden, Comparable
anstatt, Comparator
wenn diese Reihenfolge die intuitive Reihenfolge des Objekts ist. Wenn Sie beispielsweise einen Anwendungsfall zum Sortieren von Person
Objekten nach Alter haben, ist es wahrscheinlich am besten, Comparator
stattdessen nur zu verwenden .
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;
}
}
Ausgabe:
1, short
1, medium
1, very long indeed
2, short
2, medium
2, very long indeed
Der Prioritätswarteschlange ist jedem Element eine Priorität zugewiesen. Das Element mit der höchsten Priorität wird oben in der Warteschlange angezeigt. Nun hängt es von Ihnen ab, wie jedem Element Priorität zugewiesen werden soll. Wenn Sie dies nicht tun, wird Java dies standardmäßig tun. Das Element mit dem geringsten Wert erhält die höchste Priorität und wird daher zuerst aus der Warteschlange entfernt. Wenn es mehrere Elemente mit derselben höchsten Priorität gibt, wird die Bindung willkürlich unterbrochen. Sie können eine Reihenfolge auch mit Comparator im Konstruktor angeben PriorityQueue(initialCapacity, comparator)
Beispielcode:
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() + " ");
}
Ausgabe:
Priority queue using Comparable:
Georgia Indiana Oklahoma Texas
Priority queue using Comparator:
Texas Oklahoma Indiana Georgia
Andernfalls können Sie auch einen benutzerdefinierten Komparator definieren:
import java.util.Comparator;
public class StringLengthComparator implements Comparator<String>
{
@Override
public int compare(String x, String y)
{
//Your Own Logic
}
}
Hier ist das einfache Beispiel, das Sie für das anfängliche Lernen verwenden können:
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());
}
}
}