PriorityQueue
PriorityQueue是Java中的一个容器类,继承关系如下:
java.lang.Object
java.util.AbstractCollection<E>
java.util.AbstractQueue<E>
java.util.PriorityQueue<E>
按照文档中的描述,PriorityQueue是由堆实现的。
由于需要排序,所以PriorityQueue的构造函数可以接收一个Comparator接口的实例,以此来作为比较两个对象大小的依据。
顺带介绍一下Comparator接口,该接口是用来判断两个数之间大小关系的接口,实现该接口需要重写该接口中的一个
int compare(T a, T b) 方法
该方法返回一个int值
文档中对该方法对返回描述为
a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
即返回结果为负数,零,正数,对应a小于,等于,大于b。
我们先写一个Person类作为放在PriorityQueue中对对象。
public class Person {
private int age;
public Person(int age)
{
this.age = age;
}
public int getAge() {
return age;
}
}
接下来是一个测试类
public class Test {
public static void main(String[] args) {
Person p1 = new Person(1);
Person p2 = new Person(2);
Person p3 = new Person(3);
Person p4 = new Person(4);
Person p5 = new Person(5);
PriorityQueue<Person> pq = new PriorityQueue<>((n1,n2)->n1.getAge()-n2.getAge());
pq.offer(p3);
pq.offer(p5);
pq.offer(p2);
pq.offer(p1);
pq.offer(p4);
Iterator<Person> it = pq.iterator();
while(it.hasNext())
{
Person temp = (Person) it.next();
System.out.println(temp.getAge());
}
while(!pq.isEmpty())
{
Person p = (Person)pq.poll();
System.out.println(p.getAge());
}
}
}
在创建PriorityQueue时使用了lambda语句
PriorityQueue<Person> pq = new PriorityQueue<>((n1,n2)->n1.getAge()-n2.getAge());
然后用offer方法把创建的Person对象放入队列。然后我们用两种方法打印队列元素。
方法一 Iterator
通过迭代器来打印优先级队列重的元素
Iterator<Person> it = pq.iterator();
while(it.hasNext())
{
Person temp = (Person) it.next();
System.out.println(temp.getAge());
}
放入队列的顺序为35214,而打印出来的元素为12354
我们发现打印出来的元素并不是按照从小到大的顺序排列的。
因为,PriorityQueue是使用堆实现的,而堆只保证上层的元素大于(或小于)下层的元素,并且堆顶是最大(或最小)的元素。
方法二 取对头对象
while(!pq.isEmpty())
{
Person p = (Person)pq.poll();
System.out.println(p.getAge());
}
由于PriorityQueue继承自队列,所以我们可以使用poll()弹出队头对象,也就是堆顶对象,在弹出堆顶对象时,PriorityQueue会自动对剩余对象进行处理,保证仍然是一个大根堆(小根堆)。
放入对象的顺序为35124,而通过取队头对象,打印出来的顺序为12345,符合从小到大的顺序。
结尾
在LeetCode做到 【347. 前 K 个高频元素】时,有用到PriorityQueue,由于是用堆实现的,所以在解“前n个”之类的问题时,可以将对象放入堆中,然后用取堆顶对象的方法来实现。