Как получить 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());
Использование метода Reference
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);
}
Согласно документу
Метод offer вставляет элемент, если это возможно, в противном случае возвращает false. Это отличается от метода Collection.add, который может не добавить элемент, только выбрасывая непроверенное исключение. Предложенный метод предназначен для использования, когда сбой является нормальным, а не исключительным случаем, например, в очередях с фиксированной (или «ограниченной») емкостью.
При использовании очереди с ограниченной емкостью, предложение (), как правило, предпочтительнее, чем add (), который может не вставить элемент, только вызвав исключение. И PriorityQueue - это очередь с неограниченным приоритетом, основанная на куче приоритетов.
5
указывает начальную емкость очереди?
Просто пройти соответствующую Comparator
к конструктору :
PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
Единственная разница между offer
и add
является интерфейсом, к которому они принадлежат. offer
принадлежит Queue<E>
, тогда add
как изначально видно в Collection<E>
интерфейсе. Кроме того, оба метода делают одно и то же - вставляют указанный элемент в очередь с приоритетами.
из API очереди :
Метод offer вставляет элемент, если это возможно, в противном случае возвращает false. Это отличается от метода Collection.add, который может не добавить элемент, только выбрасывая непроверенное исключение. Предложенный метод предназначен для использования, когда сбой является нормальным, а не исключительным случаем, например, в очередях с фиксированной (или «ограниченной») емкостью.
Просто, чтобы ответить на вопрос add()
против offer()
(так как другой отлично ответил imo, а это может и не быть):
Согласно JavaDoc для интерфейса Queue : «Метод offer вставляет элемент, если это возможно, в противном случае возвращает false. Это отличается от метода Collection.add, который может не добавить элемент только путем генерирования непроверенного исключения. Метод offer предназначен для использовать, когда сбой является нормальным, а не исключительным случаем, например, в очередях с фиксированной (или «ограниченной») емкостью ».
Это означает, что если вы можете добавить элемент (который всегда должен иметь место в PriorityQueue), они работают точно так же. Но если вы не можете добавить элемент, offer()
вы получите приятное и симпатичное false
возвращение, в то время как создаст add()
неприятное непроверенное исключение, которое вам не нужно в вашем коде. Если неудача при добавлении означает, что код работает должным образом и / или это то, что вы обычно проверяете, используйте offer()
. Если ошибка добавления означает, что что-то сломано, используйте add()
и обработайте полученное исключение в соответствии со спецификациями интерфейса Collection .
Они оба реализованы таким образом, чтобы полностью заполнить контракт в интерфейсе очереди, в котором указаны 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);
Я нашел ответ из обсуждения на другом форуме , где пользователь сказал: «методы offer () / add () только вставляют элемент в очередь. Если вы хотите предсказуемый порядок, вы должны использовать peek / poll, который возвращает заголовок». из очереди. "
В качестве альтернативы использованию 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
Иначе, Вы также можете определить 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());
}
}
}