PriorityQueue类
PriorityQueue是一个基于优先级的无界优先级队列。优先级队列的元素按照其自然顺序进行排序,或者根据构造队列时提供的 Comparator 进行排序,具体取决于所使用的构造方法。该队列不允许使用 null 元素也不允许插入不可比较的对象(没有实现Comparable接口的对象)。
PriorityQueue 队列的队头元素指排序规则最小那个元素。如果多个元素都是最小值则随机选一个。
PriorityQueue 是一个无界队列,但是初始的容量(实际是一个Object[]),随着不断向优先级队列添加元素,其容量会自动扩容,无需指定容量增加策略的细节。
PriorityQueue的特点
PriorityQueue的继承结构
public class PriorityQueue<E> extends AbstractQueue<E>
implements java.io.Serializable {
......
}
- PriorityQueue继承于AbstractQueue类,说明它是一个基于优先级堆的极大优先级队列。此队列按照在构造时所指定的顺序对元素排序,既可以根据元素的自然顺序来指定排序,也可以根据 Comparator 来指定,这取决于使用哪种构造方法。优先级队列不允许 null 元素。依靠自然排序的优先级队列还不允许插入不可比较的对象。
- PriorityQueue实现了Serializable接口,说明它支持序列化。public interface Serializable类通过实现 java.io.Serializable 接口以启用其序列化功能。
- PriorityQueue内部实现了Iterator接口,说明它可以进行迭代器遍历。
但是需要注意的是,使用迭代器遍历,并不能保证其优先级顺序,原因是迭代器在进行遍历时采取的是层次遍历,一层一层进行遍历,并不能保证其左右孩子的准确性,如果需要按照优先级顺序进行遍历,则需要使用for循环遍历,通过poll()方法获取其队头元素。
PriorityQueue的特性
- PriorityQueue类在Java1.5中引入并作为 Java Collections Framework 的一部分。PriorityQueue是基于优先堆的一个无界队列,这个优先队列中的元素可以默认自然排序或者通过提供的Comparator(比较器)在队列实例化的时排序。
- 优先队列不允许空值,而且不支持non-comparable(不可比较)的对象,比如用户自定义的类。优先队列要求使用Java Comparable和Comparator接口给对象排序,并且在排序时会按照优先级处理其中的元素。
- 优先队列的头是基于自然排序或者Comparator排序的最小元素。如果有多个对象拥有同样的排序,那么就可能随机地取其中任意一个。当我们获取队列时,返回队列的头对象。
- 优先队列的大小是不受限制的,但在创建时可以指定初始大小。当我们向优先队列增加元素的时候,队列大小会自动增加。
- PriorityQueue是非线程安全的,所以Java提供了PriorityBlockingQueue(实现BlockingQueue接口)用于Java多线程环境。
PriorityQueue常用API
public boolean offer(E e); //将指定的元素插入此优先级队列。不能添加null元素。否则报出空指针异常。
public boolean add(E e); //将指定的元素插入此优先级队列。不能添加null元素。与offer()方法一致,实际上,该方法内部是调用offer()方法。
public boolean remove(Object o); //删除一个指定元素,如果元素不存在则返回false。
public E peek(); //取出队头元素但不删除,如果当前队头没有元素则返回null值。
public E element(); //取出队头元素但不删除,如果当前队头没有元素则抛出异常。
public E poll(); //取出队头元素并删除,如果当前队头没有元素则返回null值。
- 常用方法实践:
import java.util.*;
public class PriorityQueueTest {
public static void main(String[] args) {
PriorityQueue<Integer> queue = new PriorityQueue<>();
//queue.offer(null); //offer方法不能添加null值
//queue.element(); //获取队头获取,但不删除元素,若没有元素抛出异常
//System.out.println(queue.peek()); //获取队头获取,若没有元素返回null值
//queue.poll(); //获取队头元素并删除,若没有元素返回null值
/**
* 添加元素
* 思考:
* (1)为什么没有指定优先级的比较原则,但是没有报错
* 答:在Integer内部提供了大小比较方式
* (2)如何提供优先级队列的比较原则(与TreeMap中提供大小比较原则相同)
* 答:相当于我们需要为优先级队列提供一个大小比较的原则,即向优先级队列提供比较器
*/
queue.offer(1);
queue.offer(999);
queue.offer(33);
queue.offer(17);
/**
* 迭代器方式遍历
* 不会按优先级高低进行遍历,会按照底层数据结构的方式进行遍历,即按照最小根堆左右子树的方式遍历
* 思考:为什么所有的元素在底层并没有按照优先级顺存储,他还能维护优先级顺序
*/
Iterator<Integer> iterator = queue.iterator();
while (iterator.hasNext()) {
Integer next = iterator.next();
System.out.println(next);
}
}
}
- 执行结果:
1
17
33
999
PriorityQueue源码分析
1、成员变量
// 默认初始化大小
privatestaticfinalintDEFAULT_INITIAL_CAPACITY = 11;
// 用数组实现的二叉堆,下面的英文注释确认了我们前面的说法。
/**
* Priority queue represented as a balanced binary heap: the two
* children of queue[n] are queue[2*n+1] and queue[2*(n+1)]. The
* priority queue is ordered by comparator, or by the elements'
* natural ordering, if comparator is null: For each node n in the
* heap and each descendant d of n, n <= d. The element with the
* lowest value is in queue[0], assuming the queue is nonempty.
*/
private transient Object[] queue ;
// 队列的元素数量
private int size = 0;
// 比较器
private final Comparator<? super E> comparator;
// 用于快速失败机制判断
private transient int modCount = 0;
2、构造方法
/**
* 默认构造方法,使用默认的初始大小来构造一个优先队列,比较器comparator为空,这里要求入队的元素必须实现Comparator接口
*/
public PriorityQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}