Змініть приоритетну чергу до максимальної черги


124

У мене черга пріоритету на Java цілих категорій:

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

Коли я телефоную, pq.poll()я отримую мінімальний елемент.

Питання: як змінити код, щоб отримати максимальний елемент?


4
Я думаю, ви повинні використовувати конструктор, який отримує для цього компаратор. Використовуйте Collections.reverseOrder для отримання зворотного компаратора.
Едвін Далорцо

1
вам потрібно здати компаратор. дивіться stackoverflow.com/questions/683041/…
DarthVader

Це може допомогти: tech693.blogspot.com/2018/09/…
Гуру Java

Відповіді:


232

Як щодо цього:

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()Забезпечує , Comparatorщо б впорядкувати елементи в PriorityQueueу вигляді на протилежному порядку в їх природному порядку в цьому випадку.


14
Collections.reverseOrder()також перевантажений, щоб взяти компаратор, тому він також працює, якщо порівнювати власні об'єкти.
літаючі вівці

14
У PriorityQueue Java 8 є новий конструктор, який просто приймає компаратор як аргумент PriorityQueue(Comparator<? super E> comparator).
abhisheknirmal

75

Ви можете використовувати лямбда-вираз з 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 і повертає 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
Гуантонг, Шень

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

Це ідеально і робить саме те, що було запропоновано, перетворивши міні-купу в макс.
Камран

2
використання b-aможе викликати, overflowтому слід уникати його використання, а також використовувати Collections.reverseOrder();як компаратор або замінювати ба, на 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)

Метод порівняння за замовчуванням повертає від'ємне ціле число, нуль або додатне ціле число, оскільки перший аргумент менший, рівний або більший, ніж другий.

Пріоритетна черга за замовчуванням, що надається 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

Зміна черги PriorityQue на MAX PriorityQueue Метод 1: Черга pq = нова PriorityQueue <> (Collections.reverseOrder ()); Спосіб 2: Черга pq1 = нова черговість PriorityQue <> ((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

         */


    }
}

Візьмемо відоме інтерв'ю Проблема: Найбільший елемент в масиві за допомогою 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

         */
    }
}

Як ми бачимо, обидва дають однаковий результат.


3

Цього можна досягти, використовуючи

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

1

Я щойно провів моделювання Монте-Карло на обох компараторах на подвійній купі сортування min max, і обидва вони прийшли до однакового результату:

Це максимальні компаратори, які я використав:

(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;якщо (rhs> lhs) повернути -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;
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.