ฉันมีลำดับความสำคัญของคิวใน Java of Integers:
PriorityQueue<Integer> pq= new PriorityQueue<Integer>();
เมื่อฉันโทรหาpq.poll()
ฉันจะได้รับองค์ประกอบขั้นต่ำ
คำถาม: จะเปลี่ยนรหัสอย่างไรเพื่อให้ได้องค์ประกอบสูงสุด?
ฉันมีลำดับความสำคัญของคิวใน Java of Integers:
PriorityQueue<Integer> pq= new PriorityQueue<Integer>();
เมื่อฉันโทรหาpq.poll()
ฉันจะได้รับองค์ประกอบขั้นต่ำ
คำถาม: จะเปลี่ยนรหัสอย่างไรเพื่อให้ได้องค์ประกอบสูงสุด?
คำตอบ:
เป็นอย่างไรบ้าง:
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()
จัดเตรียม a Comparator
ที่จะจัดเรียงองค์ประกอบPriorityQueue
ในแบบเรียงซ้อนตามลำดับธรรมชาติในกรณีนี้
Collections.reverseOrder()
นอกจากนี้ยังมีการใช้งานตัวเปรียบเทียบมากเกินไปดังนั้นจึงใช้งานได้เช่นกันหากคุณเปรียบเทียบวัตถุที่กำหนดเอง
PriorityQueue(Comparator<? super E> comparator)
แถวคอยลำดับความสำคัญมีตัวสร้างใหม่ซึ่งใช้เวลาเพียงเปรียบเทียบเป็นอาร์กิวเมนต์
คุณสามารถใช้ lambda expression ได้ตั้งแต่ 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());
ฟังก์ชันแลมบ์ดาจะใช้จำนวนเต็มสองจำนวนเป็นพารามิเตอร์อินพุตลบออกจากกันและส่งกลับผลลัพธ์เลขคณิต ฟังก์ชันแลมบ์ดาใช้อินเทอร์เฟซการทำงาน, Comparator<T>
. (ใช้แทนคลาสที่ไม่ระบุชื่อหรือการใช้งานแบบไม่ต่อเนื่อง)
(x, y) -> y - x
อาจไม่เหมาะสมสำหรับจำนวนเต็มแบบยาวเนื่องจากล้น ตัวอย่างเช่นตัวเลข y = จำนวนเต็ม.MIN_VALUEและ x = 5 ให้ผลลัพธ์เป็นจำนวนบวก new PriorityQueue<>((x, y) -> Integer.compare(y, x))
มันจะดีกว่าที่จะใช้ แต่ทางออกที่ดีกว่าที่จะได้รับจาก @Edwin Dalorzo Collections.reverseOrder()
กับการใช้งาน
คุณสามารถระบุ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;
}
});
ตอนนี้ลำดับความสำคัญจะย้อนกลับการเปรียบเทียบทั้งหมดดังนั้นคุณจะได้รับองค์ประกอบสูงสุดแทนที่จะเป็นองค์ประกอบขั้นต่ำ
หวังว่านี่จะช่วยได้!
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
สามารถทำให้เกิดoverflow
ดังนั้นควรหลีกเลี่ยงการใช้และควรใช้Collections.reverseOrder();
เป็นตัวเปรียบเทียบหรือแทนที่ ba Integer.compare(a,b);
ซึ่งได้เพิ่มเข้ามาJava 8
ใน 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));
องค์ประกอบของลำดับความสำคัญจะเรียงลำดับตามลำดับปกติหรือโดยตัวเปรียบเทียบที่ให้ไว้ในเวลาสร้างคิว
ตัวเปรียบเทียบควรแทนที่วิธีการเปรียบเทียบ
int compare(T o1, T o2)
วิธีเปรียบเทียบเริ่มต้นจะส่งคืนจำนวนเต็มลบศูนย์หรือจำนวนเต็มบวกเนื่องจากอาร์กิวเมนต์แรกน้อยกว่าเท่ากับหรือมากกว่าครั้งที่สอง
Default PriorityQueue ที่จัดเตรียมโดย Java คือ 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 ()
นี่คือตัวอย่าง Max-Heap ใน 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());
ผลลัพธ์จะเป็น 10
สิ่งนี้สามารถทำได้โดยโค้ดด้านล่างใน Java 8 ซึ่งได้แนะนำตัวสร้างที่ใช้ตัวเปรียบเทียบเท่านั้น
PriorityQueue<Integer> maxPriorityQ = new PriorityQueue<Integer>(Collections.reverseOrder());
เปลี่ยน PriorityQueue เป็น MAX PriorityQueue Method 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
*/
}
}
มาสัมภาษณ์ปัญหาที่มีชื่อเสียง: Kth องค์ประกอบที่ใหญ่ที่สุดในอาร์เรย์โดยใช้ 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
*/
}
}
อีกวิธีหนึ่ง:
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
*/
}
}
อย่างที่เราเห็นทั้งสองอย่างให้ผลลัพธ์เหมือนกัน
ซึ่งสามารถทำได้โดยใช้
PriorityQueue<Integer> pq = new PriorityQueue<Integer>(Collections.reverseOrder());
ฉันเพิ่งใช้การจำลองแบบมอนติคาร์โลบนตัวเปรียบเทียบทั้งสองในการเรียงลำดับฮีปคู่ขั้นต่ำสูงสุดและทั้งคู่ก็ได้ผลลัพธ์เดียวกัน:
นี่คือตัวเปรียบเทียบสูงสุดที่ฉันใช้:
(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;
if (rhs> lhs) return -1;
คุณสามารถลองทำสิ่งต่างๆเช่น:
PriorityQueue<Integer> pq = new PriorityQueue<>((x, y) -> -1 * Integer.compare(x, y));
ซึ่งใช้ได้กับฟังก์ชันการเปรียบเทียบพื้นฐานอื่น ๆ ที่คุณอาจมี
PriorityQueue<Integer> lowers = new PriorityQueue<>((o1, o2) -> -1 * o1.compareTo(o2));
คุณสามารถลองผลักองค์ประกอบด้วยเครื่องหมายย้อนกลับ เช่น: เพื่อเพิ่ม a = 2 & b = 5 แล้วสำรวจความคิดเห็น b = 5
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.add(-a);
pq.add(-b);
System.out.print(-pq.poll());
เมื่อคุณสำรวจความคิดเห็นของหัวหน้าคิวแล้วให้กลับป้ายสำหรับการใช้งานของคุณ สิ่งนี้จะพิมพ์ 5 (องค์ประกอบที่ใหญ่กว่า) สามารถใช้ในการใช้งานที่ไร้เดียงสา ไม่ใช่การแก้ไขที่เชื่อถือได้แน่นอน ฉันไม่แนะนำมัน
เราสามารถทำได้โดยสร้างคลาสCustomComparatorของเราที่ใช้อินเทอร์เฟซตัวเปรียบเทียบและลบล้างวิธีการเปรียบเทียบ ด้านล่างนี้คือรหัสสำหรับเดียวกัน:
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;
}
}