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?
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?
Câu trả lời:
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 Comparator
mà sẽ sắp xếp các yếu tố trong PriorityQueue
mộ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.
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.
PriorityQueue(Comparator<? super E> comparator)
.
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.)
(x, y) -> y - x
có 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()
.
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!
if (rhs < lhs) return +1;
if (rhs > lhs) return -1;
if (lhs < rhs) return +1; if (lhs > rhs) return -1;
PriorityQueue<Integer> pq = new PriorityQueue<Integer> (
new Comparator<Integer> () {
public int compare(Integer a, Integer b) {
return b - a;
}
}
);
b-a
có thể gây ra overflow
rấ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
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));
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 ()
Đâ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
Đ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());
Bạn có thể sử dụng MinMaxPriorityQueue
(nó là một phần của thư viện Guava):
đây là tài liệu . Thay vào đó poll()
, bạn cần gọi pollLast()
phương thức.
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ả.
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;
}
});
if (rhs < lhs) return +1;
if (rhs> lhs) return -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ó.
PriorityQueue<Integer> lowers = new PriorityQueue<>((o1, o2) -> -1 * o1.compareTo(o2));
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ó.
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;
}
}