Làm thế nào để tôi có được một PriorityQueue
sắp xếp trên những gì tôi muốn nó sắp xếp trên?
Làm thế nào để tôi có được một PriorityQueue
sắp xếp trên những gì tôi muốn nó sắp xếp trên?
Câu trả lời:
Sử dụng quá tải hàm tạo có một Comparator<? super E> comparator
và vượt qua trong một bộ so sánh so sánh theo cách thích hợp cho thứ tự sắp xếp của bạn. Nếu bạn đưa ra một ví dụ về cách bạn muốn sắp xếp, chúng tôi có thể cung cấp một số mã mẫu để triển khai trình so sánh nếu bạn không chắc chắn. (Mặc dù nó khá đơn giản.)
Như đã nói ở nơi khác: offer
và add
chỉ là các triển khai phương thức giao diện khác nhau. Trong nguồn JDK tôi đã nhận, add
các cuộc gọi offer
. Mặc dù add
và offer
có khả năng có hành vi khác nhau nói chung do khả năng offer
chỉ ra rằng giá trị không thể được thêm vào do giới hạn kích thước, sự khác biệt này không liên quan trong PriorityQueue
đó không bị ràng buộc.
Dưới đây là ví dụ về sắp xếp hàng đợi ưu tiên theo độ dài chuỗi:
// 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;
}
}
Đây là đầu ra:
ngắn
Trung bình
thực sự rất dài
compare
thực hiện return x.length() - y.length()
? (Tránh dự đoán chi nhánh)
add()
cho hoạt động thêm, thì remove()
cảm thấy hợp lý; nếu tôi đang sử dụng offer()
có lẽ tôi sẽ sử dụng poll()
... nhưng đó chỉ là một sở thích cá nhân.
Chúng tôi có thể sử dụng lambda expression
hoặc method reference
giới thiệu trong Java 8. Trong trường hợp chúng tôi có một số giá trị Chuỗi được lưu trữ trong Hàng đợi ưu tiên (có dung lượng 5), chúng tôi có thể cung cấp trình so sánh nội tuyến (dựa trên độ dài của Chuỗi):
Sử dụng biểu thức lambda
PriorityQueue<String> pq=
new PriorityQueue<String>(5,(a,b) -> a.length() - b.length());
Sử dụng tham chiếu Phương thức
PriorityQueue<String> pq=
new PriorityQueue<String>(5, Comparator.comparing(String::length));
Sau đó, chúng ta có thể sử dụng bất kỳ trong số họ như:
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());
}
}
Điều này sẽ in:
Apple
PineApple
Custard Apple
Để đảo ngược thứ tự (để thay đổi nó thành hàng đợi ưu tiên tối đa) chỉ cần thay đổi thứ tự trong bộ so sánh nội tuyến hoặc sử dụng reversed
như:
PriorityQueue<String> pq = new PriorityQueue<String>(5,
Comparator.comparing(String::length).reversed());
Chúng tôi cũng có thể sử dụng Collections.reverseOrder
:
PriorityQueue<Integer> pqInt = new PriorityQueue<>(10, Collections.reverseOrder());
PriorityQueue<String> pq = new PriorityQueue<String>(5,
Collections.reverseOrder(Comparator.comparing(String::length))
Vì vậy, chúng ta có thể thấy rằng Collections.reverseOrder
quá tải để có bộ so sánh có thể hữu ích cho các đối tượng tùy chỉnh. Thực reversed
tế sử dụng Collections.reverseOrder
:
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
Theo tài liệu
Phương thức chào hàng chèn một phần tử nếu có thể, nếu không trả về false. Điều này khác với phương thức Collection.add, có thể không thêm một phần tử chỉ bằng cách ném một ngoại lệ không được kiểm tra. Phương thức ưu đãi được thiết kế để sử dụng khi thất bại là một điều bình thường, thay vì xảy ra đặc biệt, ví dụ, trong các hàng đợi có công suất cố định (hoặc "giới hạn").
Khi sử dụng hàng đợi bị giới hạn dung lượng, Offer () thường thích hợp hơn để thêm (), điều này có thể không chèn một phần tử chỉ bằng cách ném một ngoại lệ. Và PriorityQueue là một hàng đợi ưu tiên không giới hạn dựa trên một đống ưu tiên.
5
chỉ ra khả năng bắt đầu của hàng đợi?
Chỉ cần chuyển thích hợp Comparator
cho các nhà xây dựng :
PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
Sự khác biệt duy nhất giữa offer
và add
là giao diện họ thuộc về. offer
thuộc về Queue<E>
, trong khi add
ban đầu được nhìn thấy trong Collection<E>
giao diện. Ngoài ra, cả hai phương thức đều thực hiện chính xác cùng một điều - chèn phần tử đã chỉ định vào hàng đợi ưu tiên.
từ API hàng đợi :
Phương thức chào hàng chèn một phần tử nếu có thể, nếu không trả về false. Điều này khác với phương thức Collection.add, có thể không thêm một phần tử chỉ bằng cách ném một ngoại lệ không được kiểm tra. Phương thức ưu đãi được thiết kế để sử dụng khi thất bại là một điều bình thường, thay vì xảy ra đặc biệt, ví dụ, trong các hàng đợi có công suất cố định (hoặc "giới hạn").
Chỉ cần trả lời câu hỏi add()
vs offer()
(vì câu hỏi còn lại được trả lời hoàn hảo, và điều này có thể không):
Theo JavaDoc trên Queue giao diện , "Phương thức chào hàng sẽ chèn một phần tử nếu có thể, nếu không thì trả về false. Điều này khác với phương thức Collection.add, có thể không thêm một phần tử chỉ bằng cách ném một ngoại lệ không được kiểm tra. Phương thức chào hàng được thiết kế cho sử dụng khi thất bại là một điều bình thường, thay vì xảy ra đặc biệt, ví dụ, trong các hàng đợi có công suất cố định (hoặc "giới hạn"). "
Điều đó có nghĩa là nếu bạn có thể thêm phần tử (luôn luôn là trường hợp trong PriorityQueue), chúng hoạt động chính xác như nhau. Nhưng nếu bạn không thể thêm phần tử, offer()
sẽ mang lại cho bạn một kết quả tốt và đẹp false
, đồng thời add()
ném ra một ngoại lệ khó kiểm soát mà bạn không muốn trong mã của mình. Nếu không thêm nghĩa là mã đang hoạt động như dự định và / hoặc đó là thứ bạn sẽ kiểm tra bình thường, hãy sử dụng offer()
. Nếu không thêm nghĩa là một cái gì đó bị hỏng, hãy sử dụng add()
và xử lý ngoại lệ kết quả được ném theo thông số kỹ thuật của giao diện Bộ sưu tập .
Cả hai đều được triển khai theo cách này để hoàn thành hợp đồng trên giao diện Hàng đợi chỉ định offer()
không thành công bằng cách trả về false
( phương thức được ưu tiên trong hàng đợi giới hạn dung lượng ) và cũng duy trì hợp đồng trên giao diện Bộ sưu tập luôn chỉ định add()
thất bại bằng cách ném ngoại lệ .
Dù sao, hy vọng rằng làm rõ ít nhất là một phần của câu hỏi.
Ở đây, chúng ta có thể định nghĩa bộ so sánh do người dùng định nghĩa:
Mã dưới đây:
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());
}
}
}
Đầu ra:
india pakistan bangladesh
Sự khác biệt giữa cung cấp và thêm phương thức: liên kết
Vượt qua nó a Comparator
. Điền vào loại bạn muốn thay choT
Sử dụng lambdas (Java 8+):
int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, (e1, e2) -> { return e1.compareTo(e2); });
Cách cổ điển, sử dụng lớp ẩn danh:
int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, new Comparator<T> () {
@Override
public int compare(T e1, T e2) {
return e1.compareTo(e2);
}
});
Để sắp xếp theo thứ tự ngược lại, chỉ cần trao đổi e1, e2.
Tôi cũng đã tự hỏi về thứ tự in. Hãy xem xét trường hợp này, ví dụ:
Đối với hàng đợi ưu tiên:
PriorityQueue<String> pq3 = new PriorityQueue<String>();
Mã này:
pq3.offer("a");
pq3.offer("A");
có thể in khác với:
String[] sa = {"a", "A"};
for(String s : sa)
pq3.offer(s);
Tôi đã tìm thấy câu trả lời từ một cuộc thảo luận trên một diễn đàn khác , nơi một người dùng nói, "các phương thức Offer () / add () chỉ chèn phần tử vào hàng đợi. Nếu bạn muốn một thứ tự dự đoán, bạn nên sử dụng peek / poll trả lại đầu của hàng đợi. "
Là một thay thế cho việc sử dụng Comparator
, bạn cũng có thể có các lớp học mà bạn đang sử dụng trong bạn PriorityQueue
thực hiệnComparable
(và tương ứng ghi đè lên các compareTo
phương pháp).
Lưu ý rằng nói chung tốt nhất là chỉ sử dụng Comparable
thay vì Comparator
nếu thứ tự đó là thứ tự trực quan của đối tượng - ví dụ, nếu bạn có trường hợp sử dụng để sắp xếp Person
các đối tượng theo độ tuổi, có lẽ tốt nhất chỉ nên sử dụng Comparator
thay thế.
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;
}
}
Đầu ra:
1, short
1, medium
1, very long indeed
2, short
2, medium
2, very long indeed
Hàng đợi ưu tiên có một số ưu tiên được gán cho từng thành phần, Phần tử có mức ưu tiên cao nhất xuất hiện ở Top Of Queue. Bây giờ, nó phụ thuộc vào bạn như thế nào bạn muốn ưu tiên được gán cho từng yếu tố. Nếu bạn không, Java sẽ làm theo cách mặc định. Phần tử có giá trị nhỏ nhất được gán mức ưu tiên cao nhất và do đó được loại bỏ khỏi hàng đợi trước. Nếu có một số yếu tố có cùng mức ưu tiên cao nhất, cà vạt bị phá vỡ tùy ý. Bạn cũng có thể chỉ định một đơn đặt hàng bằng Trình so sánh trong hàm tạo PriorityQueue(initialCapacity, comparator)
Mã ví dụ:
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() + " ");
}
Đầu ra:
Priority queue using Comparable:
Georgia Indiana Oklahoma Texas
Priority queue using Comparator:
Texas Oklahoma Indiana Georgia
Khác, bạn cũng có thể xác định so sánh tùy chỉnh:
import java.util.Comparator;
public class StringLengthComparator implements Comparator<String>
{
@Override
public int compare(String x, String y)
{
//Your Own Logic
}
}
Đây là ví dụ đơn giản mà bạn có thể sử dụng cho việc học ban đầu:
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());
}
}
}