web-dev-qa-db-fra.com

Comment itérer sur une PriorityQueue?

for (Event e : pq)

ne pas itérer dans l'ordre de priorité.

while(!pq.isEmpty()){
  Event e = pq.poll();
}

Cela fonctionne mais vide la file d'attente.

26
simpatico

Depuis le Javadocs :

Il n'est pas garanti que l'itérateur fourni dans la méthode iterator() traverse les éléments de PriorityQueue dans un ordre particulier. Si vous avez besoin d'une traversée ordonnée, envisagez d'utiliser Arrays.sort(pq.toArray()).

Il existe probablement d'autres mécanismes équivalents.

23

Vous ne pouvez pas parcourir une file d'attente prioritaire dans cet ordre en raison de l'implémentation sous-jacente (je pense que c'est min-heap en Java). Ce n'est pas un tableau trié de sorte que vous pouvez simplement passer d'un élément à celui qui a la priorité la plus faible. Peeking est le temps constant parce qu'il regarde le plus petit élément. Pour obtenir le prochain (dans O (log n) fois), vous devez retirez le plus petit élément, c'est ainsi que cela fonctionne. Dequeing ne consiste pas uniquement à supprimer cet élément, la structure sous-jacente se réorganise de manière à placer en premier l’élément le moins prioritaire.

De plus, pour parcourir toute la file d'attente prioritaire, il faut une opération O (n log (n)). Ainsi, vous pouvez également simplement saisir tous les éléments de la file d'attente et les trier (également O (n log (n))), puis vous pouvez les parcourir à votre guise. Le seul inconvénient est que vous détenez une copie supplémentaire de la file d'attente. 

Néanmoins, si vous devez parcourir les données de cette manière, une file d'attente prioritaire peut ne pas être la structure de données adaptée à vos besoins. 

22
Alex Florescu

Une file d'attente prioritaire basée sur le tas garantit uniquement que le premier élément est le plus haut/le plus bas. Il n’existe pas de moyen économique (c’est-à-dire O(n)) d’obtenir les éléments sous forme triée.

Si vous devez le faire souvent, envisagez d'utiliser une structure qui conserve les éléments sous forme triée. Par exemple, utilisez Java.util.TreeSet et utilisez pollFirst() ou pollLast() à la place de peek()/poll()

8
Dilum Ranatunga

Les précédentes affiches disaient tout mais personne n’a un exemple complet (sauf la copie pq), alors voici:

Event[] events = pq.toArray(new Event[pq.size()]);
Arrays.sort(events, pq.comparator());
for (Event e : events) {
    System.out.println(e);
}
0
kubpica

Donc, prendre la prioritéQueue dans une liste puis le trier est une bonne option, comme mentionné ci-dessus. Voici quelques détails pour lesquels l'itérateur donne des résultats inattendus:

L'itérateur ne renvoie pas les éléments dans le bon ordre car il imprime à partir de la structure de données sous-jacente (similaire à ArrayList). ArrayList contient les données stockées de la même manière que les données dans une implémentation Array de BinaryHeap. Par exemple: 

PriorityQueue<Integer> pq = new PriorityQueue<>();
ArrayList<Integer> test = new ArrayList(Arrays.asList(6,12,7,9,2));
test.forEach(x -> pq.add(x)); 
System.out.println("Priority Queue:- "+pq); [2, 6, 7, 12, 9]

où childOf (i) vaut 2 * i + 1 et 2 * i + 2 et parentOf (i) vaut (i-1)/2 

0
yash jain

Récemment, j'ai eu le même problème. Je voulais utiliser un objet particulier de la file d'attente prioritaire, puis conserver les éléments restants préservés.

1) J'ai créé newPriorityQueue . 2) Iterator a été utilisé pour analyser chaque élément de oldQueue 3) a utilisé la méthode oldQueue.poll () pour extraire l'élément 4) a inséré l'élément 3) dans newPriorityQueue, dans le cas contraire. utilisé.

 Queue<String> newQueue = new PriorityQueue<String>(); 
    // Assuming that oldQueue have some data in it.

    Iterator<String> itr = oldQueue.iterator();
    while(itr.hasNext()){
        String str = oldQueue.poll();
        // do some processing with str
        if(strNotUsed){
            newQueue.offer(str);
        }
    }

À la fin, oldQueue sera vide . @ Autres: - suggérez un meilleur moyen si je peux faire la même chose. Je ne peux pas utiliser l'itérateur car il ne renvoie pas les éléments dans le bon ordre.

0
novice

La méthode peek() ne supprime rien de la file d'attente, mais à cause de cela, elle obtiendra continuellement la valeur maximale jusqu'à ce qu'elle IS soit vide . Je suppose que vous avez coché si elle était vide après votre boucle while, ce qui vous donnerait cette conclusion.

La seule façon de faire est de le trier vous-même ..__ Vous pouvez obtenir le comparateur d'origine comme ceci:

Event[] events = Arrays.sort(pq.toArray(), pq.comparator());
for (Event e : events) {
    // do stuff
}
0
xthexder

Vous pouvez faire une copie de la file d'attente et interroger une boucle. Dans cet exemple, pq correspond à la file d'attente prioritaire d'origine:

PriorityQueue<Your_class> pqCopy = new PriorityQueue<Your_class>(pq);
while(!pqCopy.isEmpty()){
    Your_Class obj = pqCopy.poll();
    // obj is the next ordered item in the queue
    .....
}
0
Carlos Cuesta