เปลี่ยนลำดับความสำคัญคิวเป็นคิวลำดับความสำคัญสูงสุด


125

ฉันมีลำดับความสำคัญของคิวใน Java of Integers:

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

เมื่อฉันโทรหาpq.poll()ฉันจะได้รับองค์ประกอบขั้นต่ำ

คำถาม: จะเปลี่ยนรหัสอย่างไรเพื่อให้ได้องค์ประกอบสูงสุด?


5
ฉันคิดว่าคุณควรใช้ตัวสร้างที่ได้รับตัวเปรียบเทียบสำหรับสิ่งนั้น ใช้ Collections.reverseOrder เพื่อรับตัวเปรียบเทียบแบบย้อนกลับ
Edwin Dalorzo

1
คุณต้องผ่านตัวเปรียบเทียบ ดูstackoverflow.com/questions/683041/…
DarthVader

สิ่งนี้อาจช่วยได้: tech693.blogspot.com/2018/09/…
Java Guru

คำตอบ:


233

เป็นอย่างไรบ้าง:

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ในแบบเรียงซ้อนตามลำดับธรรมชาติในกรณีนี้


14
Collections.reverseOrder()นอกจากนี้ยังมีการใช้งานตัวเปรียบเทียบมากเกินไปดังนั้นจึงใช้งานได้เช่นกันหากคุณเปรียบเทียบวัตถุที่กำหนดเอง
แกะบิน

14
Java 8 PriorityQueue(Comparator<? super E> comparator)แถวคอยลำดับความสำคัญมีตัวสร้างใหม่ซึ่งใช้เวลาเพียงเปรียบเทียบเป็นอาร์กิวเมนต์
abhisheknirmal

75

คุณสามารถใช้ 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>. (ใช้แทนคลาสที่ไม่ระบุชื่อหรือการใช้งานแบบไม่ต่อเนื่อง)


ฟังก์ชัน lambda ตั้งชื่อพารามิเตอร์อินพุต x และ y และส่งกลับ yx ซึ่งโดยพื้นฐานแล้วคลาสเปรียบเทียบ int ทำยกเว้นจะส่งคืน xy
Edi Bice

15
ตัวเปรียบเทียบเช่น(x, y) -> y - xอาจไม่เหมาะสมสำหรับจำนวนเต็มแบบยาวเนื่องจากล้น ตัวอย่างเช่นตัวเลข y = จำนวนเต็ม.MIN_VALUEและ x = 5 ให้ผลลัพธ์เป็นจำนวนบวก new PriorityQueue<>((x, y) -> Integer.compare(y, x))มันจะดีกว่าที่จะใช้ แต่ทางออกที่ดีกว่าที่จะได้รับจาก @Edwin Dalorzo Collections.reverseOrder()กับการใช้งาน
ФимаГирин

1
@ ФимаГиринนั่นคือเรื่องจริง -2147483648 - 1 กลายเป็น 2147483647
Guangtong Shen

27

คุณสามารถระบุ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;
    }
});

ตอนนี้ลำดับความสำคัญจะย้อนกลับการเปรียบเทียบทั้งหมดดังนั้นคุณจะได้รับองค์ประกอบสูงสุดแทนที่จะเป็นองค์ประกอบขั้นต่ำ

หวังว่านี่จะช่วยได้!


5
อาจจะเป็นลำดับความสำคัญสูงสุด q lhs <rhs returs +1; สิ่งที่คุณเขียนที่นี่คือ q ขั้นต่ำหลังจากการทดสอบของฉัน
sivi

สำหรับการพิมพ์แบบย้อนกลับนั่นคือหากต้องพิมพ์องค์ประกอบสูงสุดก่อนในลำดับความสำคัญควรเป็นif (rhs < lhs) return +1; if (rhs > lhs) return -1;
เตีย

@Diksha ฉันเชื่อว่ารหัสที่ฉันมีนั้นเทียบเท่ากับสิ่งที่คุณกำลังโพสต์ ฉันเพิ่งใช้ความสัมพันธ์มากกว่ามากกว่าน้อยกว่า
templatetypedef

4
จริงๆแล้วความผิดพลาดของฉัน .. ฉันหมายความว่ามันควรจะเป็นแบบนี้:if (lhs < rhs) return +1; if (lhs > rhs) return -1;
เตี้ย

1
@ShrikantPrabhu จับดี - ตอนนี้แก้ไขแล้ว!
templatetypedef

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

อะไรคือปัญหา ?
CMedina

นี่เป็นสิ่งที่สมบูรณ์แบบและทำตามที่ถูกถามโดยการเปลี่ยน min heap ให้เป็น max heap
Kamran

2
การใช้b-aสามารถทำให้เกิดoverflowดังนั้นควรหลีกเลี่ยงการใช้และควรใช้Collections.reverseOrder();เป็นตัวเปรียบเทียบหรือแทนที่ ba Integer.compare(a,b);ซึ่งได้เพิ่มเข้ามาJava 8
Yug Singh

10

ใน 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)); 

8

องค์ประกอบของลำดับความสำคัญจะเรียงลำดับตามลำดับปกติหรือโดยตัวเปรียบเทียบที่ให้ไว้ในเวลาสร้างคิว

ตัวเปรียบเทียบควรแทนที่วิธีการเปรียบเทียบ

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


4

นี่คือตัวอย่าง 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


4

สิ่งนี้สามารถทำได้โดยโค้ดด้านล่างใน Java 8 ซึ่งได้แนะนำตัวสร้างที่ใช้ตัวเปรียบเทียบเท่านั้น

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

3

คุณสามารถใช้MinMaxPriorityQueue(มันเป็นส่วนหนึ่งของห้องสมุดฝรั่ง): นี่เป็นเอกสาร แต่poll()คุณต้องเรียกใช้pollLast()เมธอดแทน


3

เปลี่ยน 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

         */
    }
}

อย่างที่เราเห็นทั้งสองอย่างให้ผลลัพธ์เหมือนกัน



1

ฉันเพิ่งใช้การจำลองแบบมอนติคาร์โลบนตัวเปรียบเทียบทั้งสองในการเรียงลำดับฮีปคู่ขั้นต่ำสูงสุดและทั้งคู่ก็ได้ผลลัพธ์เดียวกัน:

นี่คือตัวเปรียบเทียบสูงสุดที่ฉันใช้:

(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;
เตีย

คุณสามารถแก้ไขได้หากต้องการ ฉันไม่มีเวลายืนยันสิ่งที่คุณเขียน ในการตั้งค่าของฉันสิ่งที่ฉันเขียนนั้นถูกต้อง
sivi

1

คุณสามารถลองทำสิ่งต่างๆเช่น:

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

ซึ่งใช้ได้กับฟังก์ชันการเปรียบเทียบพื้นฐานอื่น ๆ ที่คุณอาจมี



0

คุณสามารถลองผลักองค์ประกอบด้วยเครื่องหมายย้อนกลับ เช่น: เพื่อเพิ่ม a = 2 & b = 5 แล้วสำรวจความคิดเห็น b = 5

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

เมื่อคุณสำรวจความคิดเห็นของหัวหน้าคิวแล้วให้กลับป้ายสำหรับการใช้งานของคุณ สิ่งนี้จะพิมพ์ 5 (องค์ประกอบที่ใหญ่กว่า) สามารถใช้ในการใช้งานที่ไร้เดียงสา ไม่ใช่การแก้ไขที่เชื่อถือได้แน่นอน ฉันไม่แนะนำมัน


0

เราสามารถทำได้โดยสร้างคลาส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;
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.