У мене черга пріоритету на Java цілих категорій:
PriorityQueue<Integer> pq= new PriorityQueue<Integer>();
Коли я телефоную, pq.poll()
я отримую мінімальний елемент.
Питання: як змінити код, щоб отримати максимальний елемент?
У мене черга пріоритету на Java цілих категорій:
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()
Забезпечує , Comparator
що б впорядкувати елементи в PriorityQueue
у вигляді на протилежному порядку в їх природному порядку в цьому випадку.
Collections.reverseOrder()
також перевантажений, щоб взяти компаратор, тому він також працює, якщо порівнювати власні об'єкти.
PriorityQueue(Comparator<? super E> comparator)
.
Ви можете використовувати лямбда-вираз з 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();
як компаратор або замінювати ба, на 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)
Метод порівняння за замовчуванням повертає від'ємне ціле число, нуль або додатне ціле число, оскільки перший аргумент менший, рівний або більший, ніж другий.
Пріоритетна черга за замовчуванням, що надається 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());
Ви можете використовувати MinMaxPriorityQueue
(це частина бібліотеки Guava):
ось документація . Замість цього poll()
потрібно викликати pollLast()
метод.
Зміна черги 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
*/
}
}
Як ми бачимо, обидва дають однаковий результат.
Я щойно провів моделювання Монте-Карло на обох компараторах на подвійній купі сортування 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;
Ви можете спробувати щось на кшталт:
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;
}
}