時折、特定の順序でキューのアイテムを処理する必要があります。優先度キューはその役割を果たすデータ構造です。Javaの優先度キューは「通常の」キューとは異なります。先入れ先出しではなく、優先度に従ってアイテムを取得します。
Javaの優先度キュー
java.util.PriorityQueue
クラスは、内部的に優先ヒープの実装を使用して、このようなデータ型の実装を提供します。JavaのPriorityQueueは増加しつづけるキューです。Java 1.5で導入され、Java SE 8で拡張されました。PriorityQueueは、以下の「優先ヒープ」データ構造によって内部的に実装されています。以下はPriorityQueueクラスの階層構造です: PriorityQueueクラスのダイアグラム:
JavaのPriorityQueueコンストラクタ
- PriorityQueue() – デフォルトの初期容量(11)でPriorityQueueを作成します。
- PriorityQueue(Collection c) – 指定されたコレクション内の要素を持つPriorityQueueを作成します。
- PriorityQueue(int initialCapacity) – 指定された初期容量でPriorityQueueを作成します。
- PriorityQueue(int initialCapacity, Comparator comparator) – 指定された初期容量とその要素の順序付けに基づいてPriorityQueueを作成します。
- PriorityQueue(PriorityQueue c) – 指定された優先度付きキューの要素を含むPriorityQueueを作成します。
- PriorityQueue(SortedSet c) – 指定されたソートされたセットの要素を含むPriorityQueueを作成します。
Priority Queueの要素は、Comparator
を提供しない場合は自然な順序で並べ替えられます。要素はデフォルトで昇順に並べ替えられるため、キューの先頭は優先度が最も低い要素です。同時にキューの先頭になる可能性のある2つの要素がある場合、このような引き分けは任意に決定されます。
Java PriorityQueueの例
String
の自然な順序でタスクを含むPriorityQueueを作成しましょう:
PriorityQueue tasks=new PriorityQueue();
tasks.add("task1");
tasks.add("task4");
tasks.add("task3");
tasks.add("task2");
tasks.add("task5");
これにより、タスクのPriorityQueueが作成され、それはString
の自然な順序で順序付けられます。もう一つのPriorityQueueを作成しましょう。これはタスクを自然な順序の逆順で並べ替えます。したがって、Comparatorを渡す必要があります。
PriorityQueue reverseTasks=new PriorityQueue(Comparator.reverseOrder());
reverseTasks.add("task1");
reverseTasks.add("task4");
reverseTasks.add("task3");
reverseTasks.add("task2");
reverseTasks.add("task5");
Java PriorityQueue Methods
では、PriorityQueueで使用可能なすべてのメソッドを見て、それらを使用しましょう:
-
Boolean add(E e) – このメソッドは指定された要素をキューに挿入します。このメソッドを使用して、既にキューに5つのタスクを追加しました。
-
Comparator comparator() – このメソッドは、このキュー内の要素を順序付けるために使用されるComparatorを返します。Comparatorが指定されていない場合やキューが要素の自然な順序に従ってソートされている場合はnullを返します。したがって、次のようにします:
System.out.println(tasks.comparator()); System.out.println(reverseTasks.comparator());
出力は次のようになります:
null java.util.Collections$ReverseComparator@15db9742
-
boolean contains(Object o) – 指定された要素がキューに含まれている場合はtrueを返します。”task3″がPriorityQueueのタスクに属しているかどうかを確認しましょう:
System.out.println(tasks.contains("task3"));
これは以下を出力します:
true
-
boolean offer(E e) – add()メソッドと同様に、このメソッドも要素をキューに追加します。offer()メソッドとadd()メソッドは、容量制約のあるキューの場合には実際には少し異なる動作をしますが、PriorityQueueの場合はどちらも同じです。add()とは異なり、offer()は要素をキューに追加できなかった場合でも例外をスローしません。
-
E peek() – このキューの先頭を取得します。キューが空の場合はnullを返します。つまり、最も優先度の高い要素を返します。したがって、次のコード:
System.out.println(tasks.peek()); System.out.println(reverseTasks.peek());
以下を出力します:
task1 task5
-
E poll() – このメソッドは、キューの先頭(最も高い優先順位の要素)を取得するか、キューが空の場合はnullを返します。ただし、peek()とは異なり、要素を削除します。したがって、poll()を呼び出すと:
System.out.println(“タスクのポーリング: ”+tasks.poll()); System.out.println(“リバースタスクのポーリング: ”+reverseTasks.poll());
そしてpeek:
System.out.println(“タスクのピーク: ”+tasks.peek()); System.out.println(“リバースタスクのピーク: ”+reverseTasks.peek());
次の出力が得られます:
タスクのポーリング: タスク1 リバースタスクのポーリング: タスク5 タスクのピーク: タスク2 リバースタスクのピーク: タスク4
-
int size() – キュー内の要素数を返します。
-
boolean remove(Object o) – 指定された要素をキューから削除します(存在する場合)。同じ要素が2つ存在する場合、そのうちの1つのみを削除します。
-
Object[] toArray() – キュー内のすべての要素を含む配列を返します。
-
T[] toArray(T[] a) – キュー内のすべての要素を含む配列を返し、返される配列の型は指定された配列の型です。
-
Iterator iterator() – キューのイテレータを返します。
-
void clear() – キューからすべての要素を削除します。
これら以外にも、PriorityQueue
は Collection
および Object
クラスからメソッドを継承しています。
Java PriorityQueue Time Complexity
- enqueue および dequeue メソッドの時間複雑度は O(log(n)) です。
- remove(Object) および contains(Object) メソッドの時間複雑度は線形です。
- 取得メソッドの場合、定数時間の時間複雑度を持ちます。
この優先度付きキューの実装はスレッドセーフではありません。したがって、同期されたアクセスが必要な場合は、PriorityBlockingQueue を使用する必要があります。参照: API Doc
Source:
https://www.digitalocean.com/community/tutorials/priority-queue-java