web-dev-qa-db-ja.com

Javaでの優先度キューのソート

私はPriorityQueueに整数を挿入しようとしていました、そして私はそれを知っています:

PriorityQueueの構築時にコンパレータが指定されていない場合、キューに格納されているデータのタイプのデフォルトのコンパレータが使用されます。デフォルトのコンパレータはキューを昇順で並べます

しかし、私が得ている出力はソートされた順序ではありません。以下のコードを実行した後の出力は次のとおりです:[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);
}

誰かが理由を説明できますか?

15
apprentice

PriorityQueue は、 バイナリヒープ と呼ばれるものです。 first要素が最小であるという意味でのみ、順序付け/ソートされます。言い換えると、キューの先頭にあるものだけを考慮し、残りは必要なときに「順序付け」られます。

要素は、デキューされるときにのみ順序付けされます。つまり、poll()を使用してキューから削除されます。これが、PriorityQueueがいつでも必要以上のソートを行っていないため、このように優れたパフォーマンスを実現できる理由です。

ヒープがどのように機能するかを詳しく知りたい場合は、 this MITヒープに関する講義 をお勧めします。

29
Erik Vesteraas

PriorityQueueSystem.out.print()を呼び出すと、poll()からの要素ではなく、toString()を呼び出します。 PriorityQueuetoString()を実装しないため、AbstractCollectionからのtoString()が呼び出されます。

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

ご覧のとおり、このメソッドはPriorityQueueのみを繰り返します。 PriorityQueue javadoc でわかるように:

メソッドiterator()で提供されるIteratorは、特定の順序で優先度キューの要素をトラバースすることを保証されていません。順序トラバーサルが必要な場合は、Arrays.sort(pq.toArray())の使用を検討してください。

PriorityQueueを使用したいので使用したい場合、各値をpoll()して印刷する必要があります:

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

出力:

_2
4
6
8
_
7
Florent Bayle

_Java.util.PriorityQueue_が バイナリヒープ を実装しているためです。

残念ながら、PriorityQueueを並べ替える簡単な方法はありません。キューが空になるまでpoll()オブジェクトを使用すると、要素はコンパレーターの順序になります。そのため、同様の問題に直面したときに、事後の要素の並べ替えを可能にする独自のヒープクラスを実装しました。これを多数の要素の上位Nリストに使用します。

(私は仕事でクラスを作ったので、ここに投稿する権利はありませんが、Pythonの_heap.py_をモデルにしているので、良いインスピレーションの源があります)

3
llogiq

制限のない 優先度キュー は_priority heap_に基づいています

Priority Queue.Offer()メソッドは、コンパレータなしで渡されたときにsiftUpComparable()を内部的に使用して項目を挿入します

siftUpComparableは、ヒープ条件が満たされるまで、現在の要素を親の位置(_int i = paramInt - 1 >>> 1;_)のすべての要素と比較します


siftUpComparable Nutshellのアルゴリズム(配列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.
_

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

あなたの例では:

q.offer(4);-> Inserts 4

_Result: PQ[0]=4_


q.offer(2);-> siftUpComparableは4対2およびスワップ位置を比較します(親ロケーションでの比較)

_Result: PQ[0]=2,PQ[1]=4_


q.offer(8);-> siftUpComparable 8と2を比較します(2は親ロケーションにあるため)

_Result: PQ[2]=8_


q.offer(6);:-> siftUp 6と4を比較します(位置3の親は_paramInt - 1 >>> 1;_ロジックに従って位置1です)

_Result: PQ[3]=6_


最終_PQ=[2, 4, 8, 6]_

1
evenprime

How Java priority Queueは動作すると仮定していますか?

基本的に、printステートメントはツリーを順番に走査しません。

0
coffeeaddict