Thay đổi PriorityQueue thành max priorityqueue


124

Tôi có hàng đợi ưu tiên trong Java của số nguyên:

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

Khi tôi gọi, pq.poll()tôi nhận được phần tử tối thiểu.

Câu hỏi: làm thế nào để thay đổi mã để có được phần tử tối đa?


4
Tôi nghĩ rằng bạn nên sử dụng hàm tạo nhận được một bộ so sánh cho điều đó. Sử dụng Collections.reverseOrder để lấy bộ so sánh đã đảo ngược.
Edwin Dalorzo

1
bạn cần phải vượt qua một bộ so sánh. xem stackoverflow.com/questions/683041/…
DarthVader

Điều này có thể giúp đỡ: tech693.blogspot.com/2018/09/...
Java Guru

Câu trả lời:


232

Làm thế nào về như thế này:

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

Các Collections.reverseOrder()cung cấp một Comparatormà sẽ sắp xếp các yếu tố trong PriorityQueuemột trật tự đối diện với trật tự tự nhiên của họ trong trường hợp này.


14
Collections.reverseOrder()cũng bị quá tải để lấy một bộ so sánh, vì vậy nó cũng hoạt động nếu bạn so sánh các đối tượng tùy chỉnh.
bay cừu

14
PriorityQueue của Java 8 có một hàm tạo mới, hàm này chỉ lấy bộ so sánh làm đối số PriorityQueue(Comparator<? super E> comparator).
abhisheknirmal

75

Bạn có thể sử dụng biểu thức lambda kể từ Java 8.

Mã sau sẽ in 10, lớn hơn.

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

Hàm lambda sẽ nhận hai Số nguyên làm tham số đầu vào, trừ chúng cho nhau và trả về kết quả số học. Hàm lambda thực hiện Giao diện Chức năng Comparator<T>,. (Điều này được sử dụng tại chỗ, trái ngược với một lớp ẩn danh hoặc một triển khai rời rạc.)


lambda chức năng, tên của nó thông số đầu vào x và y và lợi nhuận YX, mà về cơ bản là những gì lớp int so sánh không ngoại trừ nó trả xy
Edi Bice

15
Bộ so sánh như (x, y) -> y - xcó thể không thích hợp với các số nguyên dài do tràn. Ví dụ: các số y = Integer.MIN_VALUE và x = 5 cho kết quả là số dương. Nó là tốt hơn để sử dụng new PriorityQueue<>((x, y) -> Integer.compare(y, x)). Tuy nhiên, giải pháp tốt hơn được đưa ra bởi @Edwin Dalorzo để sử dụng Collections.reverseOrder().
Фима Гирин

1
@ ФимаГирин Đúng vậy. -2147483648 - 1 trở thành 2147483647
Guangtong Shen

27

Bạn có thể cung cấp một Comparatorđối tượng tùy chỉnh xếp hạng các phần tử theo thứ tự ngược lại:

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

Bây giờ, hàng đợi ưu tiên sẽ đảo ngược tất cả các so sánh của nó, vì vậy bạn sẽ nhận được phần tử tối đa hơn là phần tử tối thiểu.

Hi vọng điêu nay co ich!


5
có thể đối với mức ưu tiên tối đa q, lhs <rhs returs +1; những gì bạn đã viết ở đây là q tối thiểu sau khi thử nghiệm của tôi
sivi

Để in đảo ngược, đó là nếu các yếu tố cao nhất sẽ được in đầu tiên trong một hàng đợi ưu tiên, nó phải làif (rhs < lhs) return +1; if (rhs > lhs) return -1;
Tia

@Diksha Tôi tin rằng mã tôi có tương đương với những gì bạn đang đăng. Tôi vừa mới sử dụng quan hệ lớn hơn thay vì nhỏ hơn.
templatetypedef

4
thực ra, sai lầm của tôi .. Ý tôi là nó phải như thế này:if (lhs < rhs) return +1; if (lhs > rhs) return -1;
Tia

1
@ShrikantPrabhu Bắt tốt - điều đó hiện đã được khắc phục!
templatetypedef

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

Vấn đề là gì?
CMedina

Điều này là hoàn hảo và thực hiện chính xác những gì được yêu cầu bằng cách biến một đống tối thiểu thành một đống tối đa.
Kamran

2
sử dụng b-acó thể gây ra overflowrất nên tránh sử dụng nó và nên sử dụng Collections.reverseOrder();như một so sánh hoặc thay thế ba với Integer.compare(a,b);đó đã được thêm vàoJava 8
Yug Singh

10

Trong Java 8+, bạn có thể tạo hàng đợi ưu tiên tối đa thông qua một trong các phương pháp sau:

Phương pháp 1:

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

Phương pháp 2:

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

Phương pháp 3:

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

8

Các phần tử của hàng đợi ưu tiên được sắp xếp theo thứ tự tự nhiên của chúng hoặc bởi Bộ so sánh được cung cấp tại thời điểm xây dựng hàng đợi.

Bộ so sánh sẽ ghi đè phương thức so sánh.

int compare(T o1, T o2)

Phương thức so sánh mặc định trả về một số nguyên âm, 0 hoặc một số nguyên dương vì đối số đầu tiên nhỏ hơn, bằng hoặc lớn hơn đối số thứ hai.

Giá trị ưu tiên mặc định được cung cấp bởi Java là Min-Heap, nếu bạn muốn có một đống tối đa, hãy làm theo mã

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

}

Tham khảo: https://docs.oracle.com/javase/7/docs/api/java/util/PosystemQueue.html#comparator ()


4

Đây là một Max-Heap mẫu trong 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());

Đầu ra sẽ là 10


4

Điều này có thể đạt được bằng đoạn mã dưới đây trong Java 8 đã giới thiệu một phương thức khởi tạo chỉ lấy một bộ so sánh.

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


3

Thay đổi PriorityQueue thành MAX PriorityQueue Phương pháp 1: Queue pq = new PriorityQueue <> (Collections.reverseOrder ()); Cách 2: Queue pq1 = new PriorityQueue <> ((a, b) -> b - a); Hãy xem xét một số ví dụ:

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

         */


    }
}

Hãy tham gia một cuộc phỏng vấn nổi tiếng Vấn đề: Phần tử lớn nhất thứ K trong một mảng sử dụng 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

 */
    }
}

Cách khác :

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

         */
    }
}

Như chúng ta có thể thấy, cả hai đều cho cùng một kết quả.


3

Điều này có thể đạt được bằng cách sử dụng

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

1

Tôi vừa chạy một mô phỏng Monte-Carlo trên cả hai trình so sánh trên loại tối thiểu đống kép và cả hai đều đi đến cùng một kết quả:

Đây là những bộ so sánh tối đa mà tôi đã sử dụng:

(A) Bộ so sánh tích hợp bộ sưu tập

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

(B) Bộ so sánh tùy chỉnh

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

Đối với in ngược, nghĩa là nếu các phần tử cao nhất được in đầu tiên trong hàng đợi ưu tiên, thì nó phải là if (rhs < lhs) return +1;if (rhs> lhs) return -1;
Tia

Bạn có thể chỉnh sửa nó nếu bạn thích. Tôi không có thời gian để xác nhận những gì bạn đã viết. Trong thiết lập của tôi những gì tôi viết là đúng
Sivi

1

Bạn có thể thử một cái gì đó như:

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

Chức năng này hoạt động cho bất kỳ chức năng so sánh cơ sở nào khác mà bạn có thể có.



0

Bạn có thể thử đẩy các phần tử có dấu hiệu ngược lại. Vd: Thêm a = 2 & b = 5 rồi thăm dò b = 5.

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

Sau khi bạn thăm dò ý kiến ​​người đứng đầu hàng đợi, hãy đảo ngược dấu hiệu cho việc sử dụng của bạn. Điều này sẽ in 5 (phần tử lớn hơn). Có thể được sử dụng trong các triển khai ngây thơ. Chắc chắn không phải là một bản sửa lỗi đáng tin cậy. Tôi không khuyến khích nó.


0

Chúng ta có thể làm điều này bằng cách tạo lớp CustomComparator của chúng ta, lớp này triển khai giao diện Comparator và ghi đè phương thức so sánh của nó. Dưới đây là mã cho cùng một:

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;
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.