ฉันPriorityQueue
จะจัดเรียงในสิ่งที่ฉันต้องการเรียงลำดับได้อย่างไร
ฉันPriorityQueue
จะจัดเรียงในสิ่งที่ฉันต้องการเรียงลำดับได้อย่างไร
คำตอบ:
ใช้ Constructor Overload ซึ่งใช้เวลาComparator<? super E> comparator
และผ่านไปในตัวเปรียบเทียบที่เปรียบเทียบในวิธีที่เหมาะสมสำหรับการเรียงลำดับของคุณ หากคุณให้ตัวอย่างว่าคุณต้องการเรียงลำดับอย่างไรเราสามารถให้โค้ดตัวอย่างบางส่วนเพื่อนำเครื่องมือเปรียบเทียบมาใช้หากคุณไม่แน่ใจ (มันค่อนข้างตรงไปตรงมาแม้ว่า)
ดังที่ได้กล่าวไว้ในที่อื่น ๆ : offer
และadd
เป็นเพียงวิธีการใช้งานอินเตอร์เฟสที่แตกต่างกัน ในแหล่ง JDK ฉันมี, สายadd
offer
แม้ว่าadd
และoffer
มีอาจเป็นพฤติกรรมที่แตกต่างกันในเนื่องจากทั่วไปเพื่อความสามารถในการoffer
ที่จะแสดงให้เห็นว่าค่าที่ไม่สามารถเพิ่มเนื่องจากข้อ จำกัด ของขนาดแตกต่างนี้จะไม่เกี่ยวข้องในPriorityQueue
ซึ่งเป็นมากมาย
นี่คือตัวอย่างของลำดับความสำคัญของการเรียงลำดับตามความยาวสตริง:
// 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;
}
}
นี่คือผลลัพธ์:
สั้น
กลาง
นานมากแน่นอน
compare
ดำเนินการไม่ควรเป็นเพียงแค่return x.length() - y.length()
? (หลีกเลี่ยงการคาดคะเนสาขา)
add()
สำหรับการดำเนินการเพิ่มแล้วremove()
รู้สึกสมเหตุสมผล ถ้าฉันใช้offer()
ฉันอาจจะใช้poll()
... แต่นั่นเป็นเพียงความชอบส่วนตัว
เราสามารถใช้lambda expression
หรือmethod reference
แนะนำใน Java 8 ในกรณีที่เรามีค่าสตริงบางอย่างที่เก็บไว้ใน Priority Queue (มีความจุ 5) เราสามารถให้ inline comparator (ขึ้นอยู่กับความยาวของ String):
การใช้แลมบ์ดาแสดงออก
PriorityQueue<String> pq=
new PriorityQueue<String>(5,(a,b) -> a.length() - b.length());
ใช้วิธีการอ้างอิง
PriorityQueue<String> pq=
new PriorityQueue<String>(5, Comparator.comparing(String::length));
จากนั้นเราสามารถใช้พวกเขาเป็น:
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());
}
}
สิ่งนี้จะพิมพ์:
Apple
PineApple
Custard Apple
ในการกลับคำสั่งซื้อ (เพื่อเปลี่ยนเป็นคิวลำดับความสำคัญสูงสุด) เพียงแค่เปลี่ยนลำดับในตัวเปรียบเทียบแบบอินไลน์หรือใช้reversed
เป็น:
PriorityQueue<String> pq = new PriorityQueue<String>(5,
Comparator.comparing(String::length).reversed());
เรายังสามารถใช้Collections.reverseOrder
:
PriorityQueue<Integer> pqInt = new PriorityQueue<>(10, Collections.reverseOrder());
PriorityQueue<String> pq = new PriorityQueue<String>(5,
Collections.reverseOrder(Comparator.comparing(String::length))
ดังนั้นเราจะเห็นว่าCollections.reverseOrder
มีการใช้งานมากเกินไปในการเปรียบเทียบซึ่งจะเป็นประโยชน์สำหรับวัตถุที่กำหนดเอง การreversed
ใช้งานจริงCollections.reverseOrder
:
default Comparator<T> reversed() {
return Collections.reverseOrder(this);
}
ตามเอกสาร
วิธีการเสนอแทรกองค์ประกอบถ้าเป็นไปได้มิฉะนั้นกลับเท็จ สิ่งนี้แตกต่างจากเมธอด Collection.add ซึ่งสามารถล้มเหลวในการเพิ่มองค์ประกอบโดยการโยนข้อยกเว้นที่ไม่ได้ตรวจสอบเท่านั้น วิธีการเสนอถูกออกแบบมาเพื่อใช้เมื่อความล้มเหลวเป็นเรื่องปกติแทนที่จะเกิดขึ้นเป็นพิเศษตัวอย่างเช่นในคิวที่มีความจุคงที่ (หรือ "ขอบเขต")
เมื่อใช้คิวที่ จำกัด ความจุโดยทั่วไปข้อเสนอพิเศษ () นั้นดีกว่าการเพิ่ม () ซึ่งอาจไม่สามารถแทรกองค์ประกอบได้โดยการโยนข้อยกเว้น และPriorityQueueเป็นคิวลำดับความสำคัญที่ไม่ได้ จำกัด ตามฮีปลำดับความสำคัญ
5
กำลังการผลิตเริ่มต้นของคิว?
เพียงผ่านที่เหมาะสมComparator
กับผู้สร้าง :
PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
ข้อแตกต่างระหว่างoffer
และadd
เป็นส่วนต่อประสานที่เป็นของพวกเขาเท่านั้น offer
เป็นของQueue<E>
ในขณะที่add
แต่เดิมจะเห็นในCollection<E>
อินเตอร์เฟซ นอกเหนือจากนั้นวิธีการทั้งสองทำสิ่งเดียวกัน - แทรกองค์ประกอบที่ระบุลงในคิวลำดับความสำคัญ
จากQueue API :
วิธีการเสนอแทรกองค์ประกอบถ้าเป็นไปได้มิฉะนั้นกลับเท็จ สิ่งนี้แตกต่างจากเมธอด Collection.add ซึ่งสามารถล้มเหลวในการเพิ่มองค์ประกอบโดยการโยนข้อยกเว้นที่ไม่ได้ตรวจสอบเท่านั้น วิธีการเสนอถูกออกแบบมาเพื่อใช้เมื่อความล้มเหลวเป็นเรื่องปกติแทนที่จะเกิดขึ้นเป็นพิเศษตัวอย่างเช่นในคิวที่มีความจุคงที่ (หรือ "ขอบเขต")
ไม่ต่างกันตามที่ประกาศใน javadoc:
public boolean add(E e) {
return offer(e);
}
เพียงเพื่อตอบคำถามadd()
vs offer()
(เนื่องจากอีกคำถามหนึ่งนั้นตอบคำถามได้อย่างสมบูรณ์แบบและสิ่งนี้อาจไม่ใช่):
ตามJavaDoc บน interface Queue "วิธีการเสนอแทรกองค์ประกอบถ้าเป็นไปได้มิฉะนั้นกลับเท็จนี้แตกต่างจากวิธี Collection.add ซึ่งสามารถล้มเหลวในการเพิ่มองค์ประกอบโดยการโยนข้อยกเว้นไม่ได้ตรวจสอบวิธีการเสนอถูกออกแบบมาสำหรับ ใช้เมื่อความล้มเหลวเป็นเรื่องปกติแทนที่จะเกิดขึ้นเป็นพิเศษตัวอย่างเช่นในคิวที่มีความจุคงที่ (หรือ "ขอบเขต")
ซึ่งหมายความว่าหากคุณสามารถเพิ่มองค์ประกอบ (ซึ่งควรเป็นกรณีใน PriorityQueue) สิ่งเหล่านี้จะทำงานเหมือนกันทุกประการ แต่ถ้าคุณไม่สามารถเพิ่มองค์ประกอบได้offer()
จะให้false
ผลตอบแทนที่ดีและน่าสนใจในขณะที่add()
ส่งข้อยกเว้นที่ไม่ได้ตรวจสอบที่น่ารังเกียจซึ่งคุณไม่ต้องการในรหัสของคุณ หากล้มเหลวในการเพิ่มรหัสหมายถึงคือการทำงานตามที่ตั้งใจไว้และ / offer()
หรือเป็นสิ่งที่คุณจะตรวจสอบตามปกติการใช้งาน หากล้มเหลวในการเพิ่มหมายถึงบางสิ่งบางอย่างเสียการใช้งานadd()
และการจัดการกับข้อยกเว้นที่เกิดโยนไปตามข้อกำหนดของอินเตอร์เฟซคอลเลกชัน
พวกเขาทั้งสองดำเนินการด้วยวิธีนี้จะ fullfill สัญญาในอินเตอร์เฟซคิวที่ระบุoffer()
ล้มเหลวโดยกลับfalse
( วิธีที่แนะนำในคิวกำลังการผลิตที่ จำกัด ) และยังรักษาสัญญาในอินเตอร์เฟซการเก็บที่ระบุadd()
เสมอล้มเหลวโดยการขว้างปาข้อยกเว้น
อย่างไรก็ตามหวังว่าจะชี้แจงอย่างน้อยส่วนหนึ่งของคำถาม
ในที่นี่เราสามารถกำหนดตัวเปรียบเทียบที่ผู้ใช้กำหนด:
รหัสด้านล่าง:
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());
}
}
}
ผลผลิต:
india pakistan bangladesh
ข้อแตกต่างระหว่างข้อเสนอและวิธีการเพิ่ม: ลิงก์
Comparator
ผ่านมัน กรอกประเภทที่คุณต้องการT
ใช้ lambdas (Java 8+):
int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, (e1, e2) -> { return e1.compareTo(e2); });
วิธีคลาสสิกโดยใช้คลาสที่ไม่ระบุชื่อ:
int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, new Comparator<T> () {
@Override
public int compare(T e1, T e2) {
return e1.compareTo(e2);
}
});
หากต้องการเรียงลำดับแบบย้อนกลับเพียงแค่สลับ e1, e2
ฉันยังสงสัยเกี่ยวกับการสั่งพิมพ์ พิจารณากรณีนี้ตัวอย่างเช่น:
สำหรับคิวลำดับความสำคัญ:
PriorityQueue<String> pq3 = new PriorityQueue<String>();
รหัสนี้:
pq3.offer("a");
pq3.offer("A");
อาจพิมพ์ต่างจาก:
String[] sa = {"a", "A"};
for(String s : sa)
pq3.offer(s);
ฉันพบคำตอบจากการสนทนาในฟอรัมอื่นซึ่งผู้ใช้กล่าวว่า "ข้อเสนอ () / เพิ่ม () วิธีการแทรกองค์ประกอบลงในคิวเท่านั้นหากคุณต้องการคำสั่งที่คาดเดาได้คุณควรใช้ peek / แบบสำรวจที่ส่งคืนหัว ของคิว "
เพื่อเป็นทางเลือกแทนการใช้Comparator
คุณสามารถมีคลาสที่คุณใช้ในPriorityQueue
การนำไปใช้Comparable
(และแทนที่compareTo
วิธีการ)
โปรดทราบว่าโดยทั่วไปควรใช้ให้ดีที่สุดComparable
แทนการComparator
สั่งซื้อนั้นเป็นการเรียงลำดับตามวัตถุที่เข้าใจง่าย - ตัวอย่างเช่นหากคุณมีกรณีการใช้งานเพื่อเรียงลำดับPerson
วัตถุตามอายุอาจเป็นการดีที่สุดที่จะใช้Comparator
แทน
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;
}
}
เอาท์พุท:
1, short
1, medium
1, very long indeed
2, short
2, medium
2, very long indeed
Priority Queue มีลำดับความสำคัญบางส่วนที่กำหนดให้กับแต่ละองค์ประกอบองค์ประกอบที่มีลำดับความสำคัญสูงสุดจะปรากฏที่ Top Of Queue ตอนนี้มันขึ้นอยู่กับคุณว่าคุณต้องการให้ความสำคัญกับองค์ประกอบแต่ละอย่างอย่างไร หากคุณไม่ทำเช่นนั้นจาวาจะทำตามวิธีเริ่มต้น องค์ประกอบที่มีค่าน้อยที่สุดจะถูกกำหนดลำดับความสำคัญสูงสุดและจะถูกลบออกจากคิวก่อน หากมีองค์ประกอบหลายอย่างที่มีลำดับความสำคัญสูงสุดเท่ากันเนคไทม์จะถูกทำลายโดยพลการ นอกจากนี้คุณยังสามารถระบุการสั่งซื้อโดยใช้เครื่องมือเปรียบเทียบในตัวสร้าง PriorityQueue(initialCapacity, comparator)
รหัสตัวอย่าง:
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() + " ");
}
เอาท์พุท:
Priority queue using Comparable:
Georgia Indiana Oklahoma Texas
Priority queue using Comparator:
Texas Oklahoma Indiana Georgia
อื่น ๆ คุณยังสามารถกำหนด Custom Comparator:
import java.util.Comparator;
public class StringLengthComparator implements Comparator<String>
{
@Override
public int compare(String x, String y)
{
//Your Own Logic
}
}
นี่คือตัวอย่างง่ายๆที่คุณสามารถใช้สำหรับการเรียนรู้เริ่มต้น:
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());
}
}
}