优先级队列
队列是一种先进先出(FIFO)的数据结构,但是有些情况下,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素先出队列,在这种情况下使用队列就不行了
在这种情况下,我们的数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新对象,这种数据结构就是优先级队列(PriorityQueue)。
PriorityQueue 的底层是堆,堆的底层是数组
Java集合框架中提供了PriorityQueue和PriorityBlockingQueue两种类型的优先级队列,PriorityQueue是线程不安全的,PriorityBlockingQueue是线程安全的,这里主要使用PriorityQueue。
什么是堆
堆其实就是一棵完全二叉树,它的底层是一个数组,数组中存储这棵完全二叉树层序遍历的结果,按种类分,它又分为大根堆和小根堆
堆的基本作用是快速找到集合中的最值
PriorityQueue
PriorityQueue中放置的元素必须要能够比较大小 (只有实现了 Comparable 和 Comparator 接口的类才能比较大小),不能插入无法比较大小的对象,否则会抛出 ClassCastException 异常
不能插入 null 对象,否则会抛出 NullPointerException 异常
没有容量限制,可以插入任意多个元素,其内部可以自动扩容
PriorityQueue底层使用了堆数据结构
PriorityQueue 默认情况下是小堆 --- 即每次获取到的元素都是最小的元素
如果要转换成大堆需要用户提供比较器:
PriorityQueue<Integer> queue = new PriorityQueue<Integer>(new Comparator<Integer>() {
public int compare(Integer num1, Integer num2) {
return num2 - num1;
}
});
构造方法
- PriorityQueue()
- 创建一个具有默认初始容量(11)的优先队列,该队列根据元素的自然顺序对其元素进行排序。
- PriorityQueue(int initialCapacity)
- 创建一个具有指定初始容量的优先队列,根据元素的自然顺序对元素进行排序。
- PriorityQueue(Collection<? extends E> c)
- 创建一个优先级队列,包含指定集合中的元素。如果指定的集合是 SortedSet 的实例,或者是另一个优先级队列,则此优先级队列将按照相同的顺序排序。否则,此优先级队列将根据其元素的自然顺序进行排序。
- PriorityQueue(Comparator<? super E> comparator)
- 使用默认的初始容量创建一个优先级队列,其元素根据指定的比较器进行排序。
操作方法
boolean offer(E e) 插入元素 e,插入成功返回 true,如果 e 对象为空,抛出 NullPointerException 异常,时间复杂度为 O(log2N) ,注意:空间不够时会自动扩容
E peek() 获取优先级最高的元素,如果优先级队列为空,返回 null
E poll() 移除优先级最高的元素并返回,如果优先级队列为空,返回 null
int size() 获取有效元素的个数
void clean() 清空
boolean isEmpty() 检测优先级队列是否为空,空返回 true
扩容
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
int oldCapacity = queue.length;
int newCapacity = oldCapacity + ((oldCapacity < 64) ? (oldCapacity + 2): (oldCapacity >> 1));
if (newCapacity - MAX_ARRAY_SIZE > 0) {
newCapacity = hugeCapacity(minCapacity);
}
queue = Arrays.copyOf(queue,newCapacity);
}
- 如果容量 < 64,按照 oldCapacity * 2 + 2 进行扩容
- 如果容量 >= 64,按照 oldCapacity * 1.5 进行扩容
- 如果容量超过 MAX_ARRAY_SIZE,按照 MAX_ARRAY_SIZE 进行扩容