PriorityQueueを使用するにはどうすればよいですか?


回答:


449

aを取りComparator<? super E> comparator、適切な方法で並べ替え順序を比較するコンパレーターを渡すコンストラクターオーバーロードを使用します。並べ替え方法の例を提供する場合、不明な場合は、コンパレータを実装するためのサンプルコードを提供できます。(ただし、それはかなり簡単です。)

他の場所で述べたように:offeraddは、単なるインターフェースメソッドの実装です。私が持っているJDKソースでは、をadd呼び出しますoffer。けれどもaddoffer有する潜在ための能力のために一般的に異なる挙動をoffer値がサイズ制限による追加できないことを示すために、この差はで無関係でPriorityQueue無制限です。

文字列の長さで並べ替える優先キューの例を次に示します。

// Test.java
import java.util.Comparator;
import java.util.PriorityQueue;

public class Test {
    public static void main(String[] args) {
        Comparator<String> comparator = new StringLengthComparator();
        PriorityQueue<String> queue = new PriorityQueue<String>(10, comparator);
        queue.add("short");
        queue.add("very long indeed");
        queue.add("medium");
        while (queue.size() != 0) {
            System.out.println(queue.remove());
        }
    }
}

// StringLengthComparator.java
import java.util.Comparator;

public class StringLengthComparator implements Comparator<String> {
    @Override
    public int compare(String x, String y) {
        // Assume neither string is null. Real code should
        // probably be more robust
        // You could also just return x.length() - y.length(),
        // which would be more efficient.
        if (x.length() < y.length()) {
            return -1;
        }
        if (x.length() > y.length()) {
            return 1;
        }
        return 0;
    }
}

出力は次のとおりです。

ショート

本当に長い


7
うーん...気づいた... priorityQueue.comparator()「このコレクションの順序付けに使用されるコンパレータを返します。または、このコレクションがその要素の自然順序付けに従って(Comparableを使用して)ソートされている場合はnullを返します。」それは、クラスにComparableを実装することもできるという意味ですか?
Svish

7
はい、できます。ただし、クラスに1つの自然な並べ替え順序がない限り、そうはしません。もしあれば、それは正しいことです:)
Jon Skeet

8
compare実装は正しくありませんreturn x.length() - y.length()か?(分岐予測を回避する)
フランキー2014年

7
@フランキー:そうかもしれません- 理解するのは少し難しいと思いますが、答えの目的はそれがどのように機能するかを示すことです。コメントを追加します。
Jon Skeet、2014年

2
@KarelG:違いを認識している限り、それほど重要ではないと思いますadd()追加操作に使用している場合は、remove()理にかなっていると思います。私が使用している場合offer()は、おそらくpoll()...を使用しますが、それは単なる個人的な好みです。
Jon Skeet、2015

68

Java 8ソリューション

Java 8で使用lambda expressionまたはmethod reference導入できます。プライオリティキュー(容量5)にいくつかの文字列値が格納されている場合、インライン文字列を提供できます(文字列の長さに基づく)。

ラムダ式の使用

PriorityQueue<String> pq=
                    new PriorityQueue<String>(5,(a,b) -> a.length() - b.length());

メソッドリファレンスの使用

PriorityQueue<String> pq=
                new PriorityQueue<String>(5, Comparator.comparing(String::length));

次に、それらのいずれかを次のように使用できます。

public static void main(String[] args) {
        PriorityQueue<String> pq=
                new PriorityQueue<String>(5, (a,b) -> a.length() - b.length());
       // or pq = new PriorityQueue<String>(5, Comparator.comparing(String::length));
        pq.add("Apple");
        pq.add("PineApple");
        pq.add("Custard Apple");
        while (pq.size() != 0)
        {
            System.out.println(pq.remove());
        }
    }

これは印刷されます:

Apple
PineApple
Custard Apple

順序を逆にする(最大優先度キューに変更する)には、インラインコンパレータで順序を変更するか、次のように使用reversedします。

PriorityQueue<String> pq = new PriorityQueue<String>(5, 
                             Comparator.comparing(String::length).reversed());

次も使用できますCollections.reverseOrder

PriorityQueue<Integer> pqInt = new PriorityQueue<>(10, Collections.reverseOrder());
PriorityQueue<String> pq = new PriorityQueue<String>(5, 
                Collections.reverseOrder(Comparator.comparing(String::length))

したがってCollections.reverseOrder、カスタムオブジェクトに役立つコンパレータを取得するためにオーバーロードされていることがわかります。reversed実際の用途Collections.reverseOrder

default Comparator<T> reversed() {
    return Collections.reverseOrder(this);
}

offer()とadd()

ドキュメントに従って

offerメソッドは、可能であれば要素を挿入し、そうでない場合はfalseを返します。これは、チェックされていない例外をスローすることによってのみ要素の追加に失敗する可能性があるCollection.addメソッドとは異なります。offerメソッドは、たとえば、固定容量(または「制限付き」)のキューで、例外が例外的な発生ではなく通常の発生である場合に使用するように設計されています。

容量制限のあるキューを使用する場合、通常、add()よりもoffer()の方が適しています。add()は、例外をスローすることによってのみ要素の挿入に失敗する可能性があります。また、PriorityQueueは、優先ヒープに基づく無制限の優先キューです。


5がキューの開始容量を示していると思いますか?
Neil

1
@ニールはい、私は今答えでそれをより明確にしました:)
akhil_mittal

1
Javaの8番目のバージョンは、これまでこの言語で起こった最高のことでした
GabrielBB

1
明快な例で非常に素晴らしい説明。
Vishwa Ratna

24

適切に渡すだけ Comparatorコンストラクタに

PriorityQueue(int initialCapacity, Comparator<? super E> comparator)

唯一の違いofferとはadd、彼らが属するインターフェースです。offerに属しますがQueue<E>addもともとはCollection<E>インターフェイスに表示されていました。それを除いて、両方のメソッドはまったく同じことを行います-指定された要素を優先度キューに挿入します。


7
具体的には、オファーがfalseを返している間に容量制限によりアイテムをキューに追加できない場合、add()は例外をスローします。PriorityQueuesには最大容量がないため、違いはほとんどありません。
ジェームズ

これは、add()とoffer()の明確な違いです。そして、とにかくadd()を実装する必要がありました。
ホワイトハット

19

Queue APIから:

offerメソッドは、可能であれば要素を挿入し、そうでない場合はfalseを返します。これは、チェックされていない例外をスローすることによってのみ要素の追加に失敗する可能性があるCollection.addメソッドとは異なります。offerメソッドは、たとえば、固定容量(または「制限付き」)のキューで、例外が例外的な発生ではなく通常の発生である場合に使用するように設計されています。


12

javadocで宣言されているように、違いはありません。

public boolean add(E e) {
    return offer(e);
}

6

add()vsのoffer()質問に答えるだけです(もう1つは完全にimoと答えられるため、これは当てはまらない可能性があります):

インターフェースQueueのJavaDocによると、「offerメソッドは可能であれば要素を挿入し、そうでない場合はfalseを返します。これは、チェックされていない例外をスローすることによってのみ要素の追加に失敗する可能性があるCollection.addメソッドとは異なります。offerメソッドは、障害が例外的な発生ではなく通常の発生である場合に使用します。たとえば、固定容量(または「制限付き」)キューで発生します。」

つまり、要素を追加できる場合(これは常にPriorityQueueの場合に該当します)、まったく同じように機能します。しかし、要素を追加できない場合は、コードに必要ない厄介な未チェックの例外をスローする一方でoffer()、見栄えがよくきれいなfalse戻りを提供add()します。追加に失敗した場合、コードが意図したとおりに機能しているか、通常チェックするコードである場合は、を使用しますoffer()。追加の失敗が何かが壊れていることを意味する場合、Collectionインターフェースの仕様add()に従ってスローされ結果の例外を使用して処理します

これらは両方とも、このように実装さoffer()れて、false容量制限されたキューで推奨されるメソッド)を返すことによって失敗を指定するQueueインターフェイスでコントラクトをフルフィルし、例外をスローすることで常に失敗指定add()するCollectionインターフェイスでコントラクトを維持します

とにかく、質問の少なくともその部分が明確になることを願っています。


6

ここでは、ユーザー定義のコンパレータを定義できます。

コードの下:

 import java.util.*;
 import java.util.Collections;
 import java.util.Comparator; 


 class Checker implements Comparator<String>
 {
    public int compare(String str1, String str2)
    {
        if (str1.length() < str2.length()) return -1;
        else                               return 1;
    }
 }


class Main
{  
   public static void main(String args[])
    {  
      PriorityQueue<String> queue=new PriorityQueue<String>(5, new Checker());  
      queue.add("india");  
      queue.add("bangladesh");  
      queue.add("pakistan");  

      while (queue.size() != 0)
      {
         System.out.printf("%s\n",queue.remove());
      }
   }  
}  

出力:

   india                                               
   pakistan                                         
   bangladesh

オファーと追加メソッドの違い:リンク


1
それらが等しい場合はどうなりますか?
nycynik

4

それを渡しComparatorます。代わりに希望のタイプを入力してくださいT

ラムダの使用(Java 8以降):

int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, (e1, e2) -> { return e1.compareTo(e2); });

匿名クラスを使用する古典的な方法:

int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, new Comparator<T> () {

    @Override
    public int compare(T e1, T e2) {
        return e1.compareTo(e2);
    }

});

逆の順序で並べ替えるには、単にe1とe2を入れ替えます。


3

プリント注文についても気になっていた。たとえば、次の場合を考えます。

優先キューの場合:

PriorityQueue<String> pq3 = new PriorityQueue<String>();

このコード:

pq3.offer("a");
pq3.offer("A");

とは印刷が異なる場合があります。

String[] sa = {"a", "A"}; 
for(String s : sa)   
   pq3.offer(s);

ユーザーが言った別のフォーラムでのディスカッションからの回答を見つけました。「offer()/ add()メソッドは要素をキューに挿入するだけです。予測可能な順序が必要な場合は、ヘッドを返すpeek / pollを使用する必要があります。キューの。」


3

を使用する代わりComparatorに、PriorityQueue 実装でComparable使用しているクラスを持つこともできます(それに応じてcompareToメソッドをオーバーライドします)。

一般ComparableComparator、その順序がオブジェクトの直感的な順序である場合にのみ使用するのが最善であることに注意してください。たとえば、Person年齢でオブジェクトをソートするユースケースがある場合は、Comparator代わりに使用するのがおそらく最善です。

import java.lang.Comparable;
import java.util.PriorityQueue;

class Test
{
    public static void main(String[] args)
    {
        PriorityQueue<MyClass> queue = new PriorityQueue<MyClass>();
        queue.add(new MyClass(2, "short"));
        queue.add(new MyClass(2, "very long indeed"));
        queue.add(new MyClass(1, "medium"));
        queue.add(new MyClass(1, "very long indeed"));
        queue.add(new MyClass(2, "medium"));
        queue.add(new MyClass(1, "short"));
        while (queue.size() != 0)
            System.out.println(queue.remove());
    }
}
class MyClass implements Comparable<MyClass>
{
    int sortFirst;
    String sortByLength;

    public MyClass(int sortFirst, String sortByLength)
    {
        this.sortFirst = sortFirst;
        this.sortByLength = sortByLength;
    }

    @Override
    public int compareTo(MyClass other)
    {
        if (sortFirst != other.sortFirst)
            return Integer.compare(sortFirst, other.sortFirst);
        else
            return Integer.compare(sortByLength.length(), other.sortByLength.length());
    }

    public String toString()
    {
        return sortFirst + ", " + sortByLength;
    }
}

出力:

1, short
1, medium
1, very long indeed
2, short
2, medium
2, very long indeed

1

優先度キューには、各要素にいくつかの優先度が割り当てられています。優先度が最も高い要素がキューの先頭に表示されます。ここで、各要素に優先度をどのように割り当てたいかによって異なります。そうしない場合、Javaはデフォルトの方法でそれを行います。最小値の要素には最高の優先順位が割り当てられるため、最初にキューから削除されます。同じ優先度の要素が複数ある場合、結合は任意に解除されます。コンストラクタでコンパレータを使用して順序を指定することもできます PriorityQueue(initialCapacity, comparator)

コード例:

PriorityQueue<String> queue1 = new PriorityQueue<>();
queue1.offer("Oklahoma");
queue1.offer("Indiana");
queue1.offer("Georgia");
queue1.offer("Texas");
System.out.println("Priority queue using Comparable:");
while (queue1.size() > 0) {
    System.out.print(queue1.remove() + " ");
}
PriorityQueue<String> queue2 = new PriorityQueue(4, Collections.reverseOrder());
queue2.offer("Oklahoma");
queue2.offer("Indiana");
queue2.offer("Georgia");
queue2.offer("Texas");
System.out.println("\nPriority queue using Comparator:");
while (queue2.size() > 0) {
    System.out.print(queue2.remove() + " ");
}

出力:

Priority queue using Comparable:
Georgia Indiana Oklahoma Texas 
Priority queue using Comparator:
Texas Oklahoma Indiana Georgia 

または、カスタムコンパレータを定義することもできます。

import java.util.Comparator;

public class StringLengthComparator implements Comparator<String>
{
    @Override
    public int compare(String x, String y)
    {
        //Your Own Logic
    }
}

1

以下は、初期学習に使用できる簡単な例です。

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;

public class PQExample {

    public static void main(String[] args) {
        //PriorityQueue with Comparator
        Queue<Customer> cpq = new PriorityQueue<>(7, idComp);
        addToQueue(cpq);
        pollFromQueue(cpq);
    }

    public static Comparator<Customer> idComp = new Comparator<Customer>(){

        @Override
        public int compare(Customer o1, Customer o2) {
            return (int) (o1.getId() - o2.getId());
        }

    };

    //utility method to add random data to Queue
    private static void addToQueue(Queue<Customer> cq){
        Random rand = new Random();
        for(int i=0;i<7;i++){
            int id = rand.nextInt(100);
            cq.add(new Customer(id, "KV"+id));
        }
    }


    private static void pollFromQueue(Queue<Customer> cq){
        while(true){
            Customer c = cq.poll();
            if(c == null) break;
            System.out.println("Customer Polled : "+c.getId() + " "+ c.getName());
        }
    }

}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.