我如何PriorityQueue
对我想要的东西进行排序?
我如何PriorityQueue
对我想要的东西进行排序?
Answers:
使用构造函数重载,该重载采用a 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()
...,但这只是个人喜好。
我们可以使用Java 8 lambda expression
或method reference
在Java 8中引入Java。如果我们在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方法在可能的情况下插入一个元素,否则返回false。这不同于Collection.add方法,后者只能通过引发未经检查的异常来添加元素。offer方法设计用于在正常情况下(而不是在例外情况下)发生故障(例如在固定容量(或“有界”)队列中)时使用。
当使用容量受限的队列时,offer()通常比add()更可取,因为add()可能仅通过引发异常而无法插入元素。而PriorityQueue中是一个基于优先级堆的极大优先级队列。
5
指示队列的起始容量?
只需将适当Comparator
的参数传递给构造函数即可:
PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
offer
和之间的唯一区别add
是它们所属的接口。offer
属于Queue<E>
,而add
最初在Collection<E>
接口中看到。除此之外,这两种方法的作用完全相同-将指定的元素插入优先级队列。
只是为了回答add()
vs offer()
问题(因为另一个问题在imo上得到了完美的回答,所以可能不是):
根据接口Queue上的JavaDoc的说法,“ offer方法在可能的情况下插入一个元素,否则返回false。这与Collection.add方法不同,Collection.add方法只能通过引发未经检查的异常而无法添加元素。offer方法设计用于当故障是正常情况而不是异常情况发生时使用,例如在固定容量(或“有界”)队列中。”
这意味着,如果您可以添加元素(在PriorityQueue中应该始终如此),则它们的工作原理完全相同。但是,如果您不能添加该元素,offer()
则会为您带来漂亮的false
回报,同时add()
会引发您不想在代码中使用的令人讨厌的未经检查的异常。如果添加失败表示代码按预期工作和/或您会正常检查,请使用offer()
。如果添加失败意味着有问题,请使用add()
并处理根据Collection接口的规范引发的异常。
它们既以这种方式实现,即offer()
通过返回一个false
(在容量受限的队列中首选的方法)在指定失败的Queue接口上填充合同,也通过在抛出异常的情况下维护指定add()
总是失败的Collection接口上的合同。
无论如何,希望至少可以澄清一部分问题。
在这里,我们可以定义用户定义的比较器:
下面的代码:
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
offer和add方法之间的区别:链接
通过它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。
除了使用之外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());
}
}
}