私は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);
}
誰かが理由を説明できますか?
PriorityQueue は、 バイナリヒープ と呼ばれるものです。 first要素が最小であるという意味でのみ、順序付け/ソートされます。言い換えると、キューの先頭にあるものだけを考慮し、残りは必要なときに「順序付け」られます。
要素は、デキューされるときにのみ順序付けされます。つまり、poll()
を使用してキューから削除されます。これが、PriorityQueueがいつでも必要以上のソートを行っていないため、このように優れたパフォーマンスを実現できる理由です。
ヒープがどのように機能するかを詳しく知りたい場合は、 this MITヒープに関する講義 をお勧めします。
PriorityQueue
でSystem.out.print()
を呼び出すと、poll()
からの要素ではなく、toString()
を呼び出します。 PriorityQueue
はtoString()
を実装しないため、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
_
_Java.util.PriorityQueue
_が バイナリヒープ を実装しているためです。
残念ながら、PriorityQueueを並べ替える簡単な方法はありません。キューが空になるまでpoll()
オブジェクトを使用すると、要素はコンパレーターの順序になります。そのため、同様の問題に直面したときに、事後の要素の並べ替えを可能にする独自のヒープクラスを実装しました。これを多数の要素の上位Nリストに使用します。
(私は仕事でクラスを作ったので、ここに投稿する権利はありませんが、Pythonの_heap.py
_をモデルにしているので、良いインスピレーションの源があります)
制限のない 優先度キュー は_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]
_
How Java priority Queueは動作すると仮定していますか?
基本的に、printステートメントはツリーを順番に走査しません。