1、概述
PriorityQueue 一个基于优先级的优先级队列。一定要与Collections中是sort区分开。此队列仅仅保证队首元素最小或者队首元素最大,可作为大根堆或者小根堆看待。队列中的元素按照其自然顺序(比如数值包装Integer、Long等类型,按照从小到大的顺序排序,注意,注意,注意,这个排序不是对全部元素进行排序,仅仅保证队首与剩余元素的关系。比如,如果按照自然顺序排序的话,假设有n个元素,排序后仅仅保证队首元素不大于剩下的n-1个元素,但是剩下的n-1个元素之间未必是非递减的。与Collections中的sort方法不同,sort是对所有元素进行排序,保证所有元素大小关系的一致性,左面都不大于右面或者左面都不小于后面。但是,PriorityQueue 中只保证队首与剩余元素的关系的一致性,队首不大于剩下的所有元素或者队首不小于剩下的所有元素)进行排序,或者根据构造队列时提供的 Comparator 进行排序,具体取决于所使用的构造方法。该队列不允许使用 null 元素也不允许插入不可比较的对象(没有实现Comparable接口的对象)。根据排序规则不同,PriorityQueue 队列的头指向排序规则中的最值元素。如果多个元素都是最值则随机选一个。PriorityQueue 是一个无界队列,但是初始的容量(实际是一个Object[]),随着不断向优先级队列添加元素,其容量会自动扩容,无需指定容量增加策略的细节。
2、常用方法
(1)构造方法:
PriorityQueue()使用默认的初始容量(11)创建一个 PriorityQueue,并根据其自然顺序来排序其元素(使用 Comparable)。
PriorityQueue(int initialCapacity)使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序来排序其元素(使用 Comparable)。
PriorityQueue(int initialCapacity, Comparator comparator)使用指定的初始容量创建一个 PriorityQueue,并根据指定的比较器comparator来排序其元素。
(2)peek():返回队首元素
(3)poll():返回队首元素,队首元素出队列
(4)add():添加元素
(5)size():返回队列元素个数
(6)isEmpty():判断队列是否为空,为空返回true,不空返回false
3、关于排序规则
(1)普通类型:比如Integer,Long等类型,默认使用升序的排序方式,也即默认队首是最小的元素。如果想降序排列,则要自定义降序规则。
如下:k指定了初始容量,并通过new Comparator重写了compare方法,实现了降序规则
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(k, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
案例:
import java.util.PriorityQueue;
public class Main {
public static void main(String[] args) {
PriorityQueue<Integer> queue = new PriorityQueue<>();
queue.add(0);
queue.add(5);
queue.add(1);
queue.add(3);
for(Integer fac : queue){
System.out.println(fac);
}
System.out.println("------------");
while(queue.size() != 0){
System.out.println(queue.remove());
}
}
}
打印结果:
0
3
1
5
------------
0
1
3
5
分析:元素中加入0,5,1,3后打印的结果是0,3,1,5。可见队首0是最小的元素,队首不大于剩下的元素,而且剩下的元素未必是非递减的。while循环逐个删除打印队首并删除,结果是0,1,3,5,由此可知,每次删除元素后,队列都重新进行了排序,保证队首最小。
(2)自定义类型
两种定义排序规则的方式,如同Collections中的sort方法(可以参考Java中Collections.sort()案例讲解)
(1)类实现接口
import java.util.PriorityQueue;
public class Main {
public static void main(String[] args) {
PriorityQueue<PriorityQueueTest> queue = new PriorityQueue<>();
queue.add(new PriorityQueueTest(5,"world"));
queue.add(new PriorityQueueTest(1,"bing"));
queue.add(new PriorityQueueTest(3,"bao"));
queue.add(new PriorityQueueTest(0,"hello"));
for(PriorityQueueTest fac : queue){
System.out.println(fac.num+" "+fac.name);
}
System.out.println("------------");
while(queue.size() != 0){
PriorityQueueTest removeFac = queue.remove();
System.out.println(removeFac.getNum()+ " "+ removeFac.getName());
}
}
}
class PriorityQueueTest implements Comparable<PriorityQueueTest>{
int num;
String name;
public PriorityQueueTest(int num, String name) {
this.num = num;
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 此类实现Comparable接口,重写了compareTo方法,自定义按照升序排列:按照num升序排序
@Override
public int compareTo(PriorityQueueTest o) {
return this.num - o.num;
}
}
打印结果:
0 hello
1 bing
3 bao
5 world
------------
0 hello
1 bing
3 bao
5 world
(2)在新建PriorityQueue实例时候,通过构造方法来的new Comparator参数来自定义排序规则
案例:
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
public class Main {
public static void main(String[] args) {
PriorityQueue<PriorityQueueTest> queue = new PriorityQueue<PriorityQueueTest>(new Comparator<PriorityQueueTest>() {
@Override
public int compare(PriorityQueueTest o1, PriorityQueueTest o2) {
return o2.getNum() - o1.getNum();
}
});
queue.add(new PriorityQueueTest(5,"world"));
queue.add(new PriorityQueueTest(1,"bing"));
queue.add(new PriorityQueueTest(3,"bao"));
queue.add(new PriorityQueueTest(0,"hello"));
for(PriorityQueueTest fac : queue){
System.out.println(fac.num+" "+fac.name);
}
System.out.println("------------");
while(queue.size() != 0){
PriorityQueueTest removeFac = queue.remove();
System.out.println(removeFac.getNum()+ " "+ removeFac.getName());
}
}
}
class PriorityQueueTest{
int num;
String name;
public PriorityQueueTest(int num, String name) {
this.num = num;
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
打印结果:
5 world
1 bing
3 bao
0 hello
------------
5 world
3 bao
1 bing
0 hello
可知,在PriorityQueue的构造方法中传入new Comparator,然后自定义compare方法来实现排序。
注意:PriorityQueue存储的元素要求必须是可比较的对象, 如果不是就必须明确指定比较器