我如何使用PriorityQueue?

Svi*_*ish 357 java priority-queue

我如何得到一个PriorityQueue排序我希望它排序的东西?

另外,offeradd方法之间有区别吗?

Jon*_*eet 432

使用构造函数重载,它接受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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是输出:

介质

确实很长

  • `compare`实现不应该是`return x.length() - y.length()`?(避免分支预测) (8认同)
  • 嗯......刚刚注意到...... priorityQueue.comparator()"返回用于对此集合进行排序的比较器,如果此集合根据其元素的自然顺序(使用Comparable)进行排序,则返回null." 这是否意味着我可以在我的班级上实现Comparable? (7认同)
  • @Franky:可能是,是的 - 尽管我会说*稍微难以理解,答案的目的是证明它是如何工作的.我会添加评论. (7认同)
  • 你可以,是的.我不会这样做,除非你的班级有一个自然的排序顺序.如果有的话,那是正确的做法:) (6认同)
  • @KarelG:只要你意识到差异,我就不会认为这太重要了.我想如果你使用`add()`进行添加操作,那么`remove()`感觉很合理; 如果我使用`offer()`我可能会使用`poll()`...但这只是个人偏好. (2认同)

i_a*_*ero 51

Java 8解决方案

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

使用lambda表达式

PriorityQueue<String> pq=
                    new PriorityQueue<String>(5,(a,b) -> a.length() - b.length());
Run Code Online (Sandbox Code Playgroud)

使用方法参考

PriorityQueue<String> pq=
                new PriorityQueue<String>(5, Comparator.comparing(String::length));
Run Code Online (Sandbox Code Playgroud)

然后我们可以使用它们中的任何一个:

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());
        }
    }
Run Code Online (Sandbox Code Playgroud)

这将打印:

Apple
PineApple
Custard Apple
Run Code Online (Sandbox Code Playgroud)

要反转顺序(将其更改为最大优先级队列),只需更改内联比较器中的顺序.

offer()vs add()

根据文件

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

使用容量限制队列时,offer()通常优于add(),只能通过抛出异常来插入元素.而PriorityQueue中是一个基于优先级堆的极大优先级队列.

  • Java 的第 8 版是该语言有史以来发生过的最好的事情 (3认同)

dra*_*fly 24

只需传递Comparator构造函数:

PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
Run Code Online (Sandbox Code Playgroud)

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

  • 具体来说,如果容量限制阻止将项目添加到队列,而offer返回false,则add()会抛出异常.由于PriorityQueues没有最大容量,因此差异没有实际意义. (7认同)

Pet*_*ter 18

来自Queue API:

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


d1c*_*50n 12

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

public boolean add(E e) {
    return offer(e);
}
Run Code Online (Sandbox Code Playgroud)


Jam*_*zba 12

通过它一个Comparator。填写您想要的类型代替T

使用 lambdas (Java 8+):

int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, (e1, e2) -> { return e1.compareTo(e2); });
Run Code Online (Sandbox Code Playgroud)

经典方式,使用匿名类:

int initialCapacity = 10;
PriorityQueue<T> pq = new PriorityQueue<>(initialCapacity, new Comparator<T> () {

    @Override
    public int compare(T e1, T e2) {
        return e1.compareTo(e2);
    }

});
Run Code Online (Sandbox Code Playgroud)

要以相反的顺序排序,只需交换 e1、e2。


Blu*_*ver 6

只是为了回答add()vs offer()问题(因为另一个完全回答了imo,这可能不是):

根据接口Queue上的JavaDoc,"offer方法尽可能插入一个元素,否则返回false.这与Collection.add方法不同,Collection.add方法只能通过抛出未经检查的异常来添加元素.refer方法是为当故障是正常而非异常发生时使用,例如,在固定容量(或"有界")队列中."

这意味着如果你可以添加元素(在PriorityQueue中应该总是这样),它们的工作方式完全相同.但是,如果你不能添加元素,offer()将给你一个漂亮而漂亮的false返回,同时add()抛出一个你不想在你的代码中讨厌的未经检查的异常.如果添加失败意味着代码按预期工作和/或它是您正常检查的内容,请使用offer().如果添加失败意味着某些内容被破坏,请add()根据Collection接口的规范使用和处理抛出的结果异常.

它们都实现这种方式来fullfill队列接口来指定在合同offer()通过返回失败false(方法在容量限制的队列优选),并且还保持了Collection接口,关于合同指定add()总是通过抛出异常失败.

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


ras*_*dcs 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());
      }
   }  
}  
Run Code Online (Sandbox Code Playgroud)

输出:

   india                                               
   pakistan                                         
   bangladesh
Run Code Online (Sandbox Code Playgroud)

offer和add方法之间的区别:link