Как мне использовать PriorityQueue? - PullRequest
352 голосов
/ 25 марта 2009

Как мне получить PriorityQueue для сортировки по тому, что я хочу отсортировать?

Кроме того, есть ли разница между методами offer и add?

Ответы [ 12 ]

424 голосов
/ 25 марта 2009

Используйте перегрузку конструктора, которая принимает 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;
    }
}

Вот вывод:

короткий

средний

очень долго действительно

48 голосов
/ 16 ноября 2016

Java 8 решение

Мы можем использовать 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);
}

предложение () против добавления ()

Согласно документ

Метод offer вставляет элемент, если возможно, в противном случае возвращает ложный. Это отличается от метода Collection.add, который может не добавить элемент только, выбрасывая непроверенное исключение. Предложение Метод предназначен для использования, когда отказ является нормальным, а не исключительный случай, например, в фиксированной емкости (или «ограниченный») Очереди.

При использовании очереди с ограниченной емкостью, предложение (), как правило, предпочтительнее, чем add (), который может не вставить элемент, только вызвав исключение. И PriorityQueue является неограниченной приоритетной очередью, основанной на куче приоритетов.

24 голосов
/ 25 марта 2009

Просто передайте соответствующий Comparator конструктору :

PriorityQueue(int initialCapacity, Comparator<? super E> comparator)

Единственная разница между offer и add - это интерфейс, к которому они принадлежат. offer принадлежит Queue<E>, тогда как add изначально отображается в интерфейсе Collection<E>. Кроме того, оба метода делают одно и то же - вставляют указанный элемент в очередь с приоритетами.

18 голосов
/ 03 января 2011

из API очереди :

Метод offer вставляет элемент, если возможно, в противном случае возвращает false. Это отличается от метода Collection.add, который может не добавить элемент, только выбрасывая непроверенное исключение. Метод предложения предназначен для использования, когда сбой является нормальным, а не исключительным случаем, например, в очередях с фиксированной емкостью (или «ограниченной»).

12 голосов
/ 30 ноября 2010

не отличается, как заявляют в Javadoc:

public boolean add(E e) {
    return offer(e);
}
6 голосов
/ 23 марта 2017

Здесь мы можем определить пользовательский компаратор:

Ниже код:

 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

Разница между предложением и методами добавления: ссылка

5 голосов
/ 14 апреля 2014

Просто чтобы ответить на вопрос add() против offer() (так как на другой вопрос отлично ответил imo, а это может и не быть):

В соответствии с JavaDoc на интерфейсе Queue , «Метод offer вставляет элемент, если это возможно, в противном случае возвращает false. Это отличается от метода Collection.add, который может не добавить элемент только путем броска непроверенное исключение. Метод предложения предназначен для использования, когда сбой является обычным, а не исключительным случаем, например, в очередях с фиксированной емкостью (или «ограниченных»). "

Это означает, что если вы можете добавить элемент (который всегда должен иметь место в PriorityQueue), они будут работать точно так же. Но если вы не можете добавить элемент, offer() даст вам красивое и симпатичное возвращение false, в то время как add() выдает неприятное непроверенное исключение, которое вам не нужно в вашем коде. Если неудача при добавлении означает, что код работает должным образом и / или это то, что вы обычно проверяете, используйте offer(). Если ошибка добавления означает, что что-то сломано, используйте add() и обработайте полученное исключение в соответствии с спецификациями интерфейса Collection .

Они оба реализованы таким образом, чтобы полностью заполнить контракт в интерфейсе очереди, в котором указывается ошибка offer(), возвращая false ( метод, предпочтительный в очередях с ограниченной емкостью ), а также поддерживать контракт на интерфейс Collection, который указывает add(), всегда завершается ошибкой, вызывая исключение .

В любом случае, надеюсь, что это прояснит хотя бы эту часть вопроса.

3 голосов
/ 14 января 2011

Мне также было интересно узнать о порядке печати. Рассмотрим этот случай, например:

Для очереди с приоритетами:

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, который возвращает заголовок очереди. "

2 голосов
/ 23 августа 2017

В качестве альтернативы использованию 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
1 голос
/ 21 ноября 2017

Передайте это 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.

...