Ubah priorityQueue menjadi max priorityqueue


125

Saya memiliki antrian prioritas di Java of Integers:

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

Ketika saya menelepon pq.poll()saya mendapatkan elemen minimum.

Pertanyaan: bagaimana cara mengubah kode untuk mendapatkan elemen maksimal?


5
Saya pikir Anda harus menggunakan konstruktor yang menerima pembanding untuk itu. Gunakan Collections.reverseOrder untuk mendapatkan pembanding terbalik.
Edwin Dalorzo

1
Anda harus melewati pembanding. lihat stackoverflow.com/questions/683041/…
DarthVader

Jawaban:


233

Bagaimana kalau seperti ini:

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

The Collections.reverseOrder()menyediakan Comparatoryang akan mengurutkan unsur-unsur di PriorityQueuedalam urutan yang berlawanan untuk tatanan alam mereka dalam kasus ini.


14
Collections.reverseOrder()juga kelebihan beban untuk mengambil pembanding, jadi ini juga berfungsi jika Anda membandingkan objek khusus.
domba terbang

14
PriorityQueue Java 8 memiliki konstruktor baru, yang hanya membutuhkan pembanding sebagai argumen PriorityQueue(Comparator<? super E> comparator).
abhisheknirmal

75

Anda dapat menggunakan ekspresi lambda sejak Java 8.

Kode berikut akan mencetak 10, lebih besar.

// 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());

Fungsi lambda akan mengambil dua bilangan bulat sebagai parameter masukan, menguranginya satu sama lain, dan mengembalikan hasil aritmatika. Fungsi lambda mengimplementasikan Antarmuka Fungsional Comparator<T>,. (Ini digunakan di tempat, sebagai lawan dari kelas anonim atau implementasi terpisah.)


lambda function, menamai parameter inputnya x dan y dan mengembalikan yx, yang pada dasarnya adalah apa yang dilakukan kelas pembanding int kecuali ia mengembalikan xy
Edi Bice

15
Komparator seperti (x, y) -> y - xmungkin tidak sesuai untuk bilangan bulat panjang karena melimpah. Misalnya, bilangan y = Integer.MIN_VALUE dan x = 5 menghasilkan bilangan positif. Lebih baik digunakan new PriorityQueue<>((x, y) -> Integer.compare(y, x)). Padahal, solusi yang lebih baik diberikan oleh @Edwin Dalorzo untuk digunakan Collections.reverseOrder().
Фима Гирин

1
@ ФимаГирин Itu benar. -2147483648 - 1 menjadi 2147483647
Guangtong Shen

27

Anda dapat memberikan Comparatorobjek khusus yang memberi peringkat elemen dalam urutan terbalik:

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

Sekarang, antrian prioritas akan membalikkan semua perbandingannya, jadi Anda akan mendapatkan elemen maksimum daripada elemen minimum.

Semoga ini membantu!


5
mungkin untuk prioritas maksimal q lhs <rhs returs +1; apa yang Anda tulis di sini adalah q minimum setelah pengujian saya
sivi

Untuk pencetakan terbalik, yaitu jika elemen tertinggi akan dicetak pertama kali dalam antrian prioritas, itu harusif (rhs < lhs) return +1; if (rhs > lhs) return -1;
Tia

@Diksha Saya yakin kode yang saya miliki sama dengan yang Anda posting. Saya baru saja menggunakan relasi lebih besar daripada relasi kurang dari.
templatetypedef

4
sebenarnya, kesalahanku .. Maksudku harus seperti ini:if (lhs < rhs) return +1; if (lhs > rhs) return -1;
Tia

1
@ShrikantPrabhu Tangkapan bagus - sekarang sudah diperbaiki!
templatetypedef

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

Apa masalahnya ?
CMedina

Ini sempurna dan melakukan persis seperti yang diminta dengan mengubah min heap menjadi max heap.
Kamran

2
menggunakan b-adapat menyebabkan overflowjadi harus menghindari menggunakannya dan harus menggunakan Collections.reverseOrder();sebagai pembanding atau mengganti ba dengan Integer.compare(a,b);yang telah ditambahkan diJava 8
Yug Singh

10

Di Java 8+ Anda dapat membuat antrian prioritas maksimal melalui salah satu metode berikut:

Metode 1:

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

Metode 2:

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

Metode 3:

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

8

Unsur-unsur antrian prioritas diurutkan menurut urutan aslinya, atau oleh Pembanding yang disediakan pada waktu konstruksi antrian.

Pembanding harus mengganti metode perbandingan.

int compare(T o1, T o2)

Metode perbandingan default mengembalikan bilangan bulat negatif, nol, atau bilangan bulat positif karena argumen pertama kurang dari, sama dengan, atau lebih besar dari yang kedua.

Default PriorityQueue yang disediakan oleh Java adalah Min-Heap, Jika Anda ingin max heap berikut adalah kodenya

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

}

Referensi: https://docs.oracle.com/javase/7/docs/api/java/util/PriorityQueue.html#comparator ()


4

Berikut adalah contoh Max-Heap di Java:

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());

Outputnya akan menjadi 10


4

Ini dapat dicapai dengan kode di bawah ini di Java 8 yang telah memperkenalkan konstruktor yang hanya membutuhkan pembanding.

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


3

Ubah PriorityQueue menjadi MAX PriorityQueue Metode 1: Queue pq = new PriorityQueue <> (Collections.reverseOrder ()); Metode 2: Antrian pq1 = new PriorityQueue <> ((a, b) -> b - a); Mari kita lihat beberapa Contoh:

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

         */


    }
}

Mari kita ambil wawancara terkenal Masalah: Kth Largest Element in an Array menggunakan PriorityQueue

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

 */
    }
}

Cara lain :

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

         */
    }
}

Seperti yang bisa kita lihat, keduanya memberikan hasil yang sama.


3

Ini dapat dicapai dengan menggunakan

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

1

Saya baru saja menjalankan simulasi Monte-Carlo pada kedua komparator pada tumpukan ganda jenis min max dan keduanya sampai pada hasil yang sama:

Ini adalah komparator maksimal yang telah saya gunakan:

(A) Koleksi pembanding bawaan

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

(B) Pembanding khusus

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

Untuk pencetakan terbalik, yaitu jika elemen tertinggi akan dicetak pertama kali dalam antrian prioritas, itu harus if (rhs < lhs) return +1;if (rhs> lhs) return -1;
Tia

Anda dapat mengeditnya jika Anda suka. Saya tidak punya waktu untuk mengkonfirmasi apa yang Anda tulis. Dalam pengaturan saya apa yang saya tulis benar
sivi

1

Anda dapat mencoba sesuatu seperti:

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

Yang berfungsi untuk fungsi perbandingan dasar lainnya yang mungkin Anda miliki.



0

Anda dapat mencoba mendorong elemen dengan tanda terbalik. Misalnya: Untuk menambahkan a = 2 & b = 5 dan kemudian polling b = 5.

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

Setelah Anda mengumpulkan kepala antrian, balikkan tanda untuk penggunaan Anda. Ini akan mencetak 5 (elemen yang lebih besar). Dapat digunakan dalam implementasi yang naif. Jelas bukan perbaikan yang andal. Saya tidak merekomendasikannya.


0

Kita bisa melakukan ini dengan membuat kelas CustomComparator kita yang mengimplementasikan antarmuka Comparator dan mengganti metode perbandingannya. Di bawah ini adalah kode yang sama:

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;
    }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.