priorityQueueをmax priorityqueueに変更します


124

Java of Integersに優先キューがあります:

 PriorityQueue<Integer> pq= new PriorityQueue<Integer>();

呼び出すpq.poll()と、最小要素が取得されます。

質問:コードを変更して最大の要素を取得するにはどうすればよいですか?


4
そのためのコンパレータを受け取るコンストラクタを使用する必要があると思います。Collections.reverseOrderを使用して、反転コンパレータを取得します。
Edwin Dalorzo、

1
コンパレータを渡す必要があります。stackoverflow.com/questions/683041/…を
DarthVader

このかもしれないのヘルプ:tech693.blogspot.com/2018/09/...
Javaの達人

回答:


232

このようにどうですか:

PriorityQueue<Integer> queue = new PriorityQueue<>(10, Collections.reverseOrder());
queue.offer(1);
queue.offer(2);
queue.offer(3);
//...

Integer val = null;
while( (val = queue.poll()) != null) {
    System.out.println(val);
}

Collections.reverseOrder()提供Comparator中の要素の並べ替えであろうとPriorityQueue、この場合、その自然な順序にopositeの順序で。


14
Collections.reverseOrder()また、コンパレーターを取得するためにオーバーロードされるため、カスタムオブジェクトを比較する場合にも機能します。
空飛ぶ羊

14
Java 8のPriorityQueueには、コンストラクターを引数として取る新しいコンストラクターがありますPriorityQueue(Comparator<? super E> comparator)
abhisheknirmal 2016年

75

Java 8以降、ラムダ式を使用できます。

次のコードは、大きい方の10を出力します。

// There is overflow problem when using simple lambda as comparator, as pointed out by Фима Гирин.
// PriorityQueue<Integer> pq = new PriorityQueue<>((x, y) -> y - x);

PriorityQueue<Integer> pq =new PriorityQueue<>((x, y) -> Integer.compare(y, x));

pq.add(10);
pq.add(5);
System.out.println(pq.peek());

ラムダ関数は2つの整数を入力パラメーターとして受け取り、それらを互いに減算して、算術結果を返します。ラムダ関数は、機能インターフェイスを実装しComparator<T>ます。(これは、匿名クラスや個別の実装とは対照的に、適切に使用されます。)


ラムダ関数は、入力パラメーターにxとyという名前を付けてyxを返します。これは、xyを返すことを除いて、基本的にintコンパレータクラスが行うことです
Edi Bice

15
(x, y) -> y - xオーバーフローが原因で、long整数にはlikeのようなコンパレーターが適切でない場合があります。たとえば、数値y = Integer.MIN_VALUEおよびx = 5は正の数値になります。使用することをお勧めします new PriorityQueue<>((x, y) -> Integer.compare(y, x))。ただし、@ Edwin Dalorzoがより優れたソリューションを提供するために使用していますCollections.reverseOrder()
ФимаГирин

1
@ФимаГиринそれは本当です。-2147483648-1は2147483647になります
Guangtong Shen

27

Comparator逆の順序で要素をランク付けするカスタムオブジェクトを提供できます。

PriorityQueue<Integer> pq = new PriorityQueue<Integer>(defaultSize, new Comparator<Integer>() {
    public int compare(Integer lhs, Integer rhs) {
        if (lhs < rhs) return +1;
        if (lhs.equals(rhs)) return 0;
        return -1;
    }
});

これで、優先度キューはすべての比較を逆にするため、最小要素ではなく最大要素を取得します。

お役に立てれば!


5
おそらく最大の優先度qの場合、lhs <rhs returs +1; あなたがここに書いたものは、私のテスト後の最小qです
sivi

逆印刷の場合、つまり、最も高い要素が優先キューで最初に印刷される場合、それはif (rhs < lhs) return +1; if (rhs > lhs) return -1;
Tia

@Diksha私が持っているコードはあなたが投稿しているものと同等だと思います。「より小さい」ではなく「より大きい」の関係を使用しました。
templatetypedef

4
実際、私の間違い..私はそれが次のようであるべきだと意味しました:if (lhs < rhs) return +1; if (lhs > rhs) return -1;
Tia

1
@ShrikantPrabhu良い点-これは修正されました!
templatetypedef

14
PriorityQueue<Integer> pq = new PriorityQueue<Integer> (
  new Comparator<Integer> () {
    public int compare(Integer a, Integer b) {
       return b - a;
    }
  }
);

何が問題ですか ?
CMedina 2016年

これは完璧で、最小ヒープを最大ヒープに変換することによって要求されたものを正確に実行します。
カムラン2018

2
使用b-aすると、overflowその原因が発生する可能性があるため、使用を避けCollections.reverseOrder();、コンパレータとして使用するか、Integer.compare(a,b);追加されたbaを置き換える必要がありますJava 8
Yug Singh

10

Java 8以降では、次のいずれかの方法で最大優先度キューを作成できます。

方法1:

PriorityQueue<Integer> maxPQ = new PriorityQueue<>(Collections.reverseOrder()); 

方法2:

PriorityQueue<Integer> maxPQ = new PriorityQueue<>((a,b) -> b - a); 

方法3:

PriorityQueue<Integer> maxPQ = new PriorityQueue<>((a,b) -> b.compareTo(a)); 

8

優先度キューの要素は、それらの自然な順序に従って、またはキューの構築時に提供されるコンパレーターによって順序付けられます。

コンパレータは、compareメソッドをオーバーライドする必要があります。

int compare(T o1, T o2)

デフォルトの比較メソッドは、最初の引数が2番目の引数より小さい、等しい、または大きいため、負の整数、ゼロ、または正の整数を返します。

Javaが提供するデフォルトのPriorityQueueはMin-Heapです。最大ヒープが必要な場合は、次のコードを使用してください

public class Sample {
    public static void main(String[] args) {
        PriorityQueue<Integer> q = new PriorityQueue<Integer>(new Comparator<Integer>() {

            public int compare(Integer lhs, Integer rhs) {
                if(lhs<rhs) return +1;
                if(lhs>rhs) return -1;
                return 0;
            }
        });
        q.add(13);
        q.add(4);q.add(14);q.add(-4);q.add(1);
        while (!q.isEmpty()) {
            System.out.println(q.poll());
        }
    }

}

リファレンス:https : //docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html#comparator()


4

JavaのMax-Heapの例を次に示します。

PriorityQueue<Integer> pq1= new PriorityQueue<Integer>(10, new Comparator<Integer>() {
public int compare(Integer x, Integer y) {
if (x < y) return 1;
if (x > y) return -1;
return 0;
}
});
pq1.add(5);
pq1.add(10);
pq1.add(-1);
System.out.println("Peek: "+pq1.peek());

出力は10になります


4

これは、コンパレーターのみを使用するコンストラクターを導入したJava 8の以下のコードによって実現できます。

PriorityQueue<Integer> maxPriorityQ = new PriorityQueue<Integer>(Collections.reverseOrder());


3

PriorityQueueをMAX PriorityQueueに変更するメソッド1:Queue pq = new PriorityQueue <>(Collections.reverseOrder()); 方法2:Queue pq1 = new PriorityQueue <>((a、b)-> b-a); いくつかの例を見てみましょう:

public class Example1 {
    public static void main(String[] args) {

        List<Integer> ints = Arrays.asList(222, 555, 666, 333, 111, 888, 777, 444);
        Queue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
        pq.addAll(ints);
        System.out.println("Priority Queue => " + pq);
        System.out.println("Max element in the list => " + pq.peek());
        System.out.println("......................");
        // another way
        Queue<Integer> pq1 = new PriorityQueue<>((a, b) -> b - a);
        pq1.addAll(ints);
        System.out.println("Priority Queue => " + pq1);
        System.out.println("Max element in the list => " + pq1.peek());
        /* OUTPUT
          Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222]
          Max element in the list => 888
          ......................
           Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222]
           Max element in the list => 888

         */


    }
}

有名なインタビューの問題を取り上げましょう:PriorityQueueを使用した配列内のK番目に大きい要素

public class KthLargestElement_1{
    public static void main(String[] args) {

        List<Integer> ints = Arrays.asList(222, 555, 666, 333, 111, 888, 777, 444);
        int k = 3;
        Queue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
        pq.addAll(ints);
        System.out.println("Priority Queue => " + pq);
        System.out.println("Max element in the list => " + pq.peek());
        while (--k > 0) {
            pq.poll();
        } // while
        System.out.println("Third largest => " + pq.peek());
/*
 Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222]
Max element in the list => 888
Third largest => 666

 */
    }
}

別の方法 :

public class KthLargestElement_2 {
    public static void main(String[] args) {
        List<Integer> ints = Arrays.asList(222, 555, 666, 333, 111, 888, 777, 444);
        int k = 3;

        Queue<Integer> pq1 = new PriorityQueue<>((a, b) -> b - a);
        pq1.addAll(ints);
        System.out.println("Priority Queue => " + pq1);
        System.out.println("Max element in the list => " + pq1.peek());
        while (--k > 0) {
            pq1.poll();
        } // while
        System.out.println("Third largest => " + pq1.peek());
        /*
          Priority Queue => [888, 444, 777, 333, 111, 555, 666, 222] 
          Max element in the list => 888 
          Third largest => 666

         */
    }
}

ご覧のとおり、どちらも同じ結果を出しています。


3

これは、

PriorityQueue<Integer> pq = new PriorityQueue<Integer>(Collections.reverseOrder());

1

ダブルヒープソート最小値と最大値の両方のコンパレータでモンテカルロシミュレーションを実行したところ、どちらも同じ結果が得られました。

これらは私が使用した最大のコンパレータです:

(A)コレクション組み込みコンパレータ

 PriorityQueue<Integer> heapLow = new PriorityQueue<Integer>(Collections.reverseOrder());

(B)カスタムコンパレータ

PriorityQueue<Integer> heapLow = new PriorityQueue<Integer>(new Comparator<Integer>() {
    int compare(Integer lhs, Integer rhs) {
        if (rhs > lhs) return +1;
        if (rhs < lhs) return -1;
        return 0;
    }
});

逆印刷の場合、つまり、最も高い要素が優先キューで最初に印刷されるif (rhs < lhs) return +1;場合は、(rhs> lhs)が-1を返す場合にそうする必要があります。
Tia

必要に応じて編集できます。私はあなたが書いたものを確認する時間がありません。私の設定では、私が書いたものは正しかった
sivi

1

あなたは次のようなことを試すことができます:

PriorityQueue<Integer> pq = new PriorityQueue<>((x, y) -> -1 * Integer.compare(x, y));

あなたが持っているかもしれない他のベース比較関数のために働きます。



0

逆符号で要素をプッシュしてみることができます。例:a = 2&b = 5を追加してから、b = 5をポーリングします。

PriorityQueue<Integer>  pq = new PriorityQueue<>();
pq.add(-a);
pq.add(-b);
System.out.print(-pq.poll());

キューの先頭をポーリングしたら、使用法の記号を逆にします。これは5(大きい要素)を印刷します。素朴な実装で使用できます。間違いなく信頼できる修正ではありません。お勧めしません。


0

これを行うには、Comparatorインターフェースを実装するCustomComparatorクラスを作成し、そのcompareメソッドをオーバーライドします。以下は同じコードです:

import java.util.PriorityQueue;
import java.util.Comparator;
public class Main
{
    public static void main(String[] args) {
        PriorityQueue<Integer> nums = new PriorityQueue<>(new CustomComparator());
        nums.offer(21);
        nums.offer(1);
        nums.offer(8);
        nums.offer(2);
        nums.offer(-4);
        System.out.println(nums.peek());
    }
}
class CustomComparator implements Comparator<Integer>{
    @Override
    public int compare(Integer n1, Integer n2){
        int val = n1.compareTo(n2);
        if(val > 0)
           return -1;
        else if(val < 0)
            return 1;
        else
            return 0;
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.