Як зробити так, PriorityQueue
щоб сортувати те, на що я хочу його сортувати?
Як зробити так, PriorityQueue
щоб сортувати те, на що я хочу його сортувати?
Відповіді:
Використовуйте перевантаження конструктора, яке приймає 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. Якщо у нас є деякі значення String, що зберігаються в черзі пріоритетів (ємністю 5), ми можемо надати вбудований компаратор (виходячи з довжини 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>
інтерфейсі. Крім того, що обидва способи роблять абсолютно одне і те ж - вставляйте зазначений елемент у чергу пріоритетів.
від API черги :
Метод пропозиції, якщо можливо, вставляє елемент, інакше повертає помилку. Це відрізняється від методу Collection.add, який не може додати елемент лише шляхом викидання неперевіреного винятку. Метод пропозиції призначений для використання, коли вихід з ладу є звичайним, а не винятковим явищем, наприклад, у чергах з фіксованою ємністю (або "обмеженими").
Просто щоб відповісти на запитання add()
vs offer()
(оскільки на інший ідеально відповідає imo, а це може бути не так):
Згідно з JavaDoc на черзі інтерфейсу , "Метод пропозиції, якщо це можливо, вставляє елемент, інакше повертає помилку. Це відрізняється від методу Collection.add, який не може додати елемент лише шляхом викидання неперевіреного винятку. Метод пропозиції призначений для використання, коли збій - це звичайне, а не виняткове явище, наприклад, у чергах з фіксованою ємністю (або "обмеженою") ".
Це означає, що якщо ви можете додати елемент (який завжди має бути у черзі PriorityQueue), вони працюють точно так само. Але якщо ви не можете додати елемент, offer()
ви отримаєте хороший і гарний false
прибуток, при цьому add()
викидає неприємний неперевірений виняток, який ви не хочете у своєму коді. Якщо додавання коду означає, що код працює за призначенням та / або ви перевірите це нормально, скористайтеся offer()
. Якщо неможливість додати означає, що щось порушено, використовуйте add()
та обробляйте отриманий виняток, кинутий відповідно до специфікацій інтерфейсу колекції .
Вони обидва реалізовані таким чином для повного заповнення договору на інтерфейсі черги, який визначає 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
Використання лямбдів (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);
Я знайшов відповідь з обговорення на іншому форумі , де користувач сказав: "Методи пропозиції () / додати () лише вставляють елемент у чергу. Якщо ви хочете передбачити передбачуване замовлення, слід використати заглянути / опитування, яке поверне голову" черги ".
Як альтернативу використанню 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
Черги пріоритетів мають певний пріоритет, присвоєний кожному елементу. Елемент із найвищим пріоритетом з’являється у верхній частині черги. Тепер, від вас залежить, яким чином ви хочете, щоб пріоритет був призначений кожному з елементів. Якщо цього не зробити, Java зробить це за замовчуванням. Елементу з найменшим значенням присвоюється найвищий пріоритет і тому спочатку видаляється з черги. Якщо є кілька елементів з однаковим найвищим пріоритетом, краватку розривають довільно. Ви також можете вказати замовлення за допомогою Comparator у конструкторі 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
Крім того, Ви також можете визначити спеціальний компаратор:
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());
}
}
}