我如何使用PriorityQueue?

时间:2009-03-25 19:18:38

标签: java priority-queue

如何让PriorityQueue对我希望它排序的内容进行排序?

此外,offeradd方法之间存在差异吗?

12 个答案:

答案 0 :(得分:424)

使用带有Comparator<? super E> comparator的构造函数重载并传入比较器,该比较器以适当的方式比较排序顺序。如果您举一个如何排序的示例,我们可以提供一些示例代码来实现比较器,如果您不确定的话。 (虽然这很简单。)

正如其他地方所说:offeradd只是不同的接口方法实现。在JDK源代码中,add调用offer。虽然addoffer通常会有潜在不同的行为,但由于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;
    }
}

这是输出:

  

     

介质

     确实很长时间

答案 1 :(得分:46)

Java 8解决方案

我们可以使用Java 8中引入的lambda expressionmethod reference。如果我们在Priority Queue中存储了一些String值(容量为5),我们可以提供内联比较器(基于String的长度) ):

使用lambda表达式

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()vs add()

根据doc

  

如果可能,offer方法会插入一个元素,否则返回   假。这与Collection.add方法不同,后者可能无法实现   仅通过抛出未经检查的异常来添加元素。报价   方法设计用于失败是正常的时候,而不是   特殊情况,例如,固定容量(或#34;有界&#34;)   队列。

使用容量限制队列时,offer()通常优于add(),只能通过抛出异常来插入元素。 PriorityQueue是基于优先级堆的无界优先级队列。

答案 2 :(得分:24)

只需将适当的Comparator传递给constructor

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

offeradd之间的唯一区别是它们所属的界面。 offer属于Queue<E>,而add最初位于Collection<E>界面。除此之外,两种方法完全相同 - 将指定的元素插入优先级队列。

答案 3 :(得分:18)

来自Queue API

  

如果可能,offer方法会插入一个元素,否则返回false。这与Collection.add方法不同,后者只能通过抛出未经检查的异常来添加元素。 offer方法设计用于故障是正常而非异常发生时,例如,在固定容量(或“有界”)队列中。

答案 4 :(得分:12)

没有什么不同,如在javadoc中声明:

public boolean add(E e) {
    return offer(e);
}

答案 5 :(得分:6)

在这里,我们可以定义用户定义的比较器:

  

代码如下:

 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

商品和添加方法之间的差异:link

答案 6 :(得分:5)

只是回答add() vs offer()问题(因为另一个问题完全得到了解答,而且可能不是这样):

根据JavaDoc on interface Queue,&#34;如果可能,offer方法会插入一个元素,否则返回false。这与Collection.add方法不同,后者只能通过抛出未经检查的异常来添加元素。提供方法设计用于故障是正常而非异常情况时使用,例如,在固定容量(或#34;有界&#34;)队列中。&#34;

这意味着如果你可以添加元素(在PriorityQueue中应该总是如此),它们的工作方式完全相同。但是,如果您无法添加该元素,offer()将为您提供漂亮且漂亮的false返回,而add()会抛出您不想要的令人讨厌的未经检查的异常在你的代码中。如果添加失败意味着代码按预期工作和/或它是您正常检查的内容,请使用offer()。如果添加失败意味着某些内容被破坏,请使用add()并处理根据the Collection interface's specifications引发的结果异常。

它们都以这种方式实现,以通过返回offer()method preferred in capacity-restricted queues)并在Collection接口上维护合同来填充指定false失败的Queue接口上的合同。 specifies add() always fails by throwing an exception

无论如何,希望至少澄清问题的那一部分。

答案 7 :(得分:3)

我也想知道打印顺序。考虑这种情况,例如:

对于优先级队列:

PriorityQueue<String> pq3 = new PriorityQueue<String>();

此代码:

pq3.offer("a");
pq3.offer("A");

可能与以下内容不同:

String[] sa = {"a", "A"}; 
for(String s : sa)   
   pq3.offer(s);

我从讨论中找到了答案on another forum,用户说,“offer()/ add()方法只将元素插入队列。如果你想要一个可预测的顺序,你应该使用peek / poll返回队列的头部。“

答案 8 :(得分:2)

作为使用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

答案 9 :(得分:1)

优先级队列为每个元素分配了一些优先级,具有最高优先级的元素出现在队列顶部。现在,这取决于您希望如何为每个元素分配优先级。如果不这样做,Java将以默认方式执行。具有最小值的元素被赋予最高优先级,因此首先从队列中删除。如果有多个元素具有相同的最高优先级,则可以任意打破平局。您还可以在构造函数 PriorityQueue(initialCapacity, comparator)

中使用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
    }
}

答案 10 :(得分:1)

以下是您可以用于初步学习的简单示例:

class TableModifications(BoxLayout):
    pass


class TableAccordionItem(MDAccordionItem):

    def __init__(self, **kwargs):
        super(TableAccordionItem, self).__init__(**kwargs)
        print(self.title) # this is empty, why?

    def add_widget(self, widget, *args):
        super(TableAccordionItem, self).add_widget(widget, *args)
        print(self.title) # this is empty, why?

答案 11 :(得分:1)

传递Comparator。请填写所需类型以代替T

使用lambdas(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。