1、概念:
优先级队列也是一种抽象数据类型。优先级队列中的每个元素都有优先级,而优先级高(或者低) 的将会出队,而优先级相同的则按照其在优先级队列中的顺序依次出队。常常有如下操作
- 将对象添加到队列、删除最大、最小元素
- 返回最高优先级对象
2、常用接口介绍
java 提供了 PriorityQueue 和 PriorityBlockingQueue 两种类型的优先级队列,其中后者是线程安全的,PriorityQueue 的效率会更好,以它来讲解。
1> 常用构造
PriorityQueue() 创建一个空的优先级队列,默认容量是 11
PriorityQueue(int initialCapacty) 创建一个初始容量为 initialCapacity的优先级队列
// 注意:initialCapacity 不能小于11,否则会抛出 illegalArgumentException 异常
priorityQueue(Collection<? extends E> c) 用一个集合来创建优先级队列
2> 添加/删除/获取优先级最高的元素
boolean offer(E e) // 添加元素 e,时间复杂度O(log2N),空间不够会扩容
E peek() // 获取优先级最高的元素,如果优先级队列为空,返回 null
E pool() // 移除优先级最高的元素并返回,如果优先级队列为空返回null
int size() // 获取有效元素的个数
void clear // 清空
boolean isEmpty() // 见内测优先级队列是否为空
扩容方式,见源码:
private void grow(int minCapacity) {
int oldCapacity = queue.length;
// Double size if small; else grow by 50%
int newCapacity = oldCapacity + ((oldCapacity < 64) ?
(oldCapacity + 2) :
(oldCapacity >> 1));
// overflow-conscious code
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
queue = Arrays.copyOf(queue, newCapacity);
}
如果小于 64 两倍+2的方式扩容,大于 64 会 1.5倍扩容
如果容量超过MAX_ARRAY_SIZE,按照MAX_ARRAY_SIZE来进行扩容
3.优先级队列的模拟实现
在JDK1.8 中的 PriorityQueue 底层用了堆这种数据结构,并且默认情况下是小堆,而堆是在完全二叉树的基础上进行了一些元素的调整。一下用堆模拟实现优先级队列:
public class MyPriorityQueue {
// 不再考虑扩容部分的代码
private int[] array = new int[100];
private int size = 0;
public void offer(int e) {
array[size++] = e;
shiftUp(size - 1);
}
public int poll() {
int oldValue = array[0];
array[0] = array[--size];
shiftDown(0);
return oldValue;
}
public int peek() {
return array[0];
}
}