web-dev-qa-db-fra.com

Comment utiliser une PriorityQueue?

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 ?

356
Svish

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

426
Jon Skeet

Solution Java 8

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);
}

offre () vs add ()

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é.

48
i_am_zero

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.

24
dragonfly

à 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").

18
Peter

pas différent, comme le déclare javadoc:

public boolean add(E e) {
    return offer(e);
}
12
d1ck50n

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.

6
Blueriver

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

6
rashedcs

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 ".

3
joserey

Au lieu d'utiliser Comparator , vous pouvez également définir la classe que vous utilisez dans votre PriorityQueueComparable (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
2
Dukeling

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
    }
}
1
devDeejay

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());
        }
    }

}
1
KayV

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.

1
James Wierzba