Comment puis-je obtenir un PriorityQueue
sur lequel je veux trier?
De même, existe-t-il une différence entre les méthodes offer
et add
?
Utilisez la surcharge constructeur qui prend un Comparator<? super E> comparator
et transmettez un comparateur comparant de la manière appropriée pour votre ordre de tri. Si vous donnez un exemple de la manière dont vous voulez trier, nous pouvons vous fournir un exemple de code pour implémenter le comparateur si vous n’êtes pas sûr. (C'est assez simple cependant.)
Comme il a été dit ailleurs: offer
et add
ne sont que des implémentations différentes de méthodes d'interface. Dans la source JDK que j'ai, add
appelle offer
. Bien que add
et offer
aient potentiellement un comportement différent en général en raison de la possibilité pour offer
d'indiquer que la valeur ne peut pas être ajoutée en raison de limitations de taille, cette différence est sans importance dans PriorityQueue
qui n'est pas lié.
Voici un exemple de tri prioritaire de la file d'attente par longueur de chaîne:
// 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;
}
}
Voici la sortie:
court
moyen
très longtemps en effet
Nous pouvons utiliser lambda expression
ou method reference
introduit dans Java 8. Si nous avons des valeurs de chaîne stockées dans la file d'attente de priorité (ayant une capacité de 5), nous pouvons fournir un comparateur en ligne (basé sur longueur de chaîne):
Utilisation de l'expression lambda
PriorityQueue<String> pq=
new PriorityQueue<String>(5,(a,b) -> a.length() - b.length());
Utilisation de la référence de la méthode
PriorityQueue<String> pq=
new PriorityQueue<String>(5, Comparator.comparing(String::length));
Ensuite, nous pouvons utiliser n'importe lequel d'entre eux comme:
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());
}
}
Cela va imprimer:
Apple
PineApple
Custard Apple
Pour inverser l'ordre (le changer en file d'attente à priorité maximale), il suffit de changer l'ordre dans le comparateur en ligne ou d'utiliser reversed
comme:
PriorityQueue<String> pq = new PriorityQueue<String>(5,
Comparator.comparing(String::length).reversed());
Nous pouvons aussi utiliser Collections.reverseOrder
:
PriorityQueue<Integer> pqInt = new PriorityQueue<>(10, Collections.reverseOrder());
PriorityQueue<String> pq = new PriorityQueue<String>(5,
Collections.reverseOrder(Comparator.comparing(String::length))
Nous pouvons donc voir que Collections.reverseOrder
est surchargé pour prendre un comparateur qui peut être utile pour les objets personnalisés. La reversed
utilise en réalité Collections.reverseOrder
:
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
Selon le doc
La méthode offer insère un élément si possible, sinon retourne false. Cela diffère de la méthode Collection.add, qui peut ne pas réussir à ajouter un élément uniquement en lançant une exception non contrôlée. La méthode d'offre est conçue pour être utilisée lorsque la défaillance est un événement normal plutôt qu'exceptionnel, par exemple dans les files d'attente à capacité fixe (ou "liées").
En cas d'utilisation d'une file d'attente à capacité limitée, offer () est généralement préférable avec add (), qui peut échouer lors de l'insertion d'un élément uniquement en lançant une exception. Et PriorityQueue est une file d'attente prioritaire sans limite basée sur un segment de priorité.
Passez juste approprié Comparator
au constructeur :
_PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
_
La seule différence entre offer
et add
est l'interface à laquelle ils appartiennent. offer
appartient à Queue<E>
, alors que add
est vu à l'origine dans l'interface Collection<E>
. En dehors de cela, les deux méthodes font exactement la même chose - insérez l'élément spécifié dans la file d'attente prioritaire.
à partir de API de file d'attente :
La méthode offer insère un élément si possible, sinon retourne false. Cela diffère de la méthode Collection.add, qui peut ne pas réussir à ajouter un élément uniquement en lançant une exception non contrôlée. La méthode d'offre est conçue pour être utilisée lorsque la défaillance est un événement normal plutôt qu'exceptionnel, par exemple dans les files d'attente à capacité fixe (ou "liées").
pas différent, comme le déclare javadoc:
public boolean add(E e) {
return offer(e);
}
Juste pour répondre à la question add()
vs offer()
(puisque l'autre est parfaitement répondu imo, et cela pourrait ne pas être le cas):
Selon JavaDoc sur la file d’interface , "La méthode offer insère un élément, si possible, en renvoyant false. Cela diffère de la méthode Collection.add, qui peut ne pas ajouter un élément en lançant une exception non contrôlée. La méthode d'offre est conçue pour être utilisée lorsque la défaillance est un événement normal plutôt qu'exceptionnel, par exemple dans les files d'attente à capacité fixe (ou "liées"). "
Cela signifie que si vous pouvez ajouter l'élément (ce qui devrait toujours être le cas dans une PriorityQueue), ils fonctionnent exactement de la même manière. Mais si vous ne pouvez pas ajouter l'élément, offer()
vous donnera un retour sympa et joli false
, tandis que add()
lève une mauvaise exception non vérifiée que vous ne voulez pas dans votre code. Si vous ne parvenez pas à ajouter du code, cela signifie que le code fonctionne correctement et/ou que vous vérifiez normalement, utilisez offer()
. Si l'incapacité à ajouter signifie que quelque chose est cassé, utilisez add()
et gérez l'exception résultante levée conformément à spécifications de l'interface Collection .
Ils sont tous deux implémentés de cette manière pour remplir le contrat sur l’interface de file d’attente qui spécifie offer()
échoue en renvoyant un false
( méthode recommandée dans les files d'attente à capacité limitée ), ainsi contrat sur l'interface Collection qui spécifie add()
échoue toujours en levant une exception .
Quoi qu'il en soit, espérons que cela clarifie au moins cette partie de la question.
Ici, nous pouvons définir un comparateur défini par l'utilisateur:
Code ci-dessous:
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());
}
}
}
Sortie:
india pakistan bangladesh
Différence entre les méthodes d'offre et d'ajout: lien
Je m'interrogeais également sur l'ordre d'impression. Considérons ce cas, par exemple:
Pour une file d'attente prioritaire:
PriorityQueue<String> pq3 = new PriorityQueue<String>();
Ce code:
pq3.offer("a");
pq3.offer("A");
peut imprimer différemment que:
String[] sa = {"a", "A"};
for(String s : sa)
pq3.offer(s);
J'ai trouvé la réponse à une discussion sur un autre forum , où un utilisateur a déclaré: "les méthodes offer ()/add () insèrent uniquement l'élément dans la file d'attente. Si vous souhaitez un ordre prévisible, vous devez utiliser peek/poll qui renvoie la tête de la file ".
Au lieu d'utiliser Comparator
, vous pouvez également définir la classe que vous utilisez dans votre PriorityQueue
Comparable
(et remplacez en conséquence la méthode compareTo
).
Notez qu'il est généralement préférable d'utiliser uniquement Comparable
au lieu de Comparator
si cet ordre correspond à l'ordre intuitif de l'objet. Si, par exemple, vous avez un cas d'utilisation pour trier les objets Person
par âge, il est probablement préférable d'utiliser plutôt Comparator
.
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;
}
}
Sortie:
1, short
1, medium
1, very long indeed
2, short
2, medium
2, very long indeed
La priorité de la file d'attente est associée à une priorité pour chaque élément. L'élément avec la priorité la plus élevée apparaît en haut de la file d'attente. Cela dépend maintenant de la façon dont vous souhaitez attribuer une priorité à chacun des éléments. Si vous ne le faites pas, le Java le fera par défaut. L'élément avec la valeur la plus faible se voit attribuer la priorité la plus élevée et est donc d'abord supprimé de la file d'attente. S'il existe plusieurs éléments ayant la même priorité la plus élevée, la liaison est rompue de manière arbitraire. Vous pouvez également spécifier un ordre en utilisant Comparator dans le constructeur PriorityQueue(initialCapacity, comparator)
Exemple de code:
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() + " ");
}
Sortie:
Priority queue using Comparable:
Georgia Indiana Oklahoma Texas
Priority queue using Comparator:
Texas Oklahoma Indiana Georgia
Sinon, vous pouvez également définir un comparateur personnalisé:
import Java.util.Comparator;
public class StringLengthComparator implements Comparator<String>
{
@Override
public int compare(String x, String y)
{
//Your Own Logic
}
}
Voici l'exemple simple que vous pouvez utiliser pour l'apprentissage initial:
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());
}
}
}
Passez-le a Comparator
. Remplissez le type souhaité à la place de T
Utilisation de lambdas (Java 8+):
int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, (e1, e2) -> { return e1.compareTo(e2); });
Manière classique, en utilisant la classe anonyme:
int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, new Comparator<T> () {
@Override
public int compare(T e1, T e2) {
return e1.compareTo(e2);
}
});
Pour trier dans l'ordre inverse, permutez simplement e1, e2.