web-dev-qa-db-fra.com

Tri de la file d'attente prioritaire en Java

J'essayais d'insérer les entiers dans PriorityQueue, et je sais que:

Si aucun comparateur n'est spécifié lors de la construction d'une PriorityQueue, le comparateur Par défaut du type de données stockées dans la file d'attente est utilisé. Le comparateur par défaut ordonnera La file d'attente par ordre croissant

Cependant, la sortie que je reçois n’est pas dans l’ordre trié .La sortie après avoir exécuté le code ci-dessous est: [2, 4, 8, 6]

public static void main(String args[]) {
    PriorityQueue<Integer> q = new PriorityQueue<Integer>(10);
    q.offer(4);
    q.offer(2);
    q.offer(8);
    q.offer(6);

    System.out.print(q);
}

Quelqu'un peut-il s'il vous plaît expliquer pourquoi?

14
apprentice

Un PriorityQueue est ce qu'on appelle un tas binaire . Il est seulement ordonné/trié dans le sens où l'élément first est le moins. En d'autres termes, il ne s'intéresse qu'à ce qu'il y a à l'avant de la file d'attente, les autres sont "ordonnés" en cas de besoin.

Les éléments ne sont ordonnés que lorsqu'ils sont retirés de la file d'attente, c'est-à-dire retirés de la file d'attente à l'aide de poll(). C’est la raison pour laquelle une PriorityQueue parvient à obtenir de telles performances, car elle ne fait pas plus de tri qu’elle n’a besoin à aucun moment.

Si vous voulez savoir comment les tas fonctionnent en détail, je vous recommande ceci MIT une conférence sur les tas .

28
Erik Vesteraas

Lorsque vous appelez System.out.print() sur votre PriorityQueue, il ne sera pas poll() vos éléments, mais appelez toString(). PriorityQueue n'implémente pas toString(), c'est donc le toString() de AbstractCollection qui sera appelé:

public String toString() {
    Iterator<E> i = iterator();
if (! i.hasNext())
    return "[]";

StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
    E e = i.next();
    sb.append(e == this ? "(this Collection)" : e);
    if (! i.hasNext())
    return sb.append(']').toString();
    sb.append(", ");
}
}

Comme vous pouvez le constater, cette méthode n’itère que la PriorityQueue. Comme vous pouvez le voir dans le PriorityQueue javadoc :

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

Si vous souhaitez utiliser la variable PriorityQueue telle qu'elle est destinée à être utilisée, vous devez poll() chaque valeur et l'imprimer:

while (!q.isEmpty()) {
    Integer i = q.poll();
    System.out.println(i);
}

Sortie:

2
4
6
8
7
Florent Bayle

En effet, Java.util.PriorityQueue implémente un binary heap .

Malheureusement, il n’existe pas de moyen facile de trier une PriorityQueue. Si vous poll() objets jusqu'à ce que la file d'attente soit vide, les éléments seront dans l'ordre du comparateur. C'est pourquoi, face à un problème similaire, j'ai implémenté ma propre classe de tas qui me permet de trier les éléments après coup. que j’utilise pour une liste des N premiers nombres d’un grand nombre d’éléments.

(Depuis que j'ai fait le cours au boulot, je n'ai pas le droit de le poster ici, mais c'est largement inspiré du heap.py de python, donc il y a une bonne source d'inspiration.)

3
llogiq

Une file d'attente non prioritaire prioritaire est basée sur un priority heap

La méthode Priority Queue.Offer() utilise siftUpComparable() en interne pour insérer des éléments lorsqu'elle est transmise sans comparateur

siftUpComparable compare l'élément en cours avec tous les éléments aux positions parentes (int i = paramInt - 1 >>> 1;) jusqu'à ce que la condition de tas soit remplie 


siftUpComparable Algorithm in Nutshell (si implémenté via le tableau Root = index 0):

1.Add the element to the bottom level of the heap.
2.Compare the added element with its parent; if they are in the correct order, stop.
3.If not, swap the element with its parent and return to the previous step.

Code Java

  private void siftUpComparable(int paramInt, E paramE)
  {
    Comparable localComparable = (Comparable)paramE;
    while (paramInt > 0)
    {
      int i = paramInt - 1 >>> 1;
      Object localObject = this.queue[i];
      if (localComparable.compareTo(localObject) >= 0) {
        break;
      }
      this.queue[paramInt] = localObject;
      paramInt = i;
    }
    this.queue[paramInt] = localComparable;
  }

Dans votre exemple:

q.offer(4); -> Insert 4

Result: PQ[0]=4


q.offer(2); -> siftUpComparable compare 4 à 2 et échange des positions (comparaisons aux emplacements parents) 

Result: PQ[0]=2,PQ[1]=4


q.offer(8); -> siftUpComparable Compare 8 et 2 (puisque 2 est à l'emplacement parent) 

Result: PQ[2]=8


q.offer(6);: -> siftUp Compare 6 à 4 (le parent de l'emplacement 3 est l'emplacement 1 selon la logique paramInt - 1 >>> 1;

Result: PQ[3]=6


PQ=[2, 4, 8, 6] final

1
EvenPrime

Comment la priorité Java Queue est supposée fonctionner?

Fondamentalement, votre instruction print ne traverse pas l’arbre dans l’ordre. 

0
coffeeaddict