1, 概念PriorityQueue是优先队列,作用是保证每次取出的元素都是队列中权值最小的,具体是通过完全二叉树实现的最小堆(任一位置的值都不大于其左右孩子的值)完成的。重要变量如下,
private static final long serialVersionUID = -7720805057305804111L; // 版本系列号
private static final int DEFAULT_CAPACITY = 11;
private static final double DEFAULT_INIT_CAPACITY_RATIO = 1.1;
private static final int DEFAULT_CAPACITY_RATIO = 2;
private int size; // 添加的元素
private Comparator<? super E> comparator;
private transient E[] elements;
2, 构造方法
有6个构造方法,
public PriorityQueue(int initialCapacity, Comparator<? super E> comparator) {
if (initialCapacity < 1) {
throw new IllegalArgumentException("initialCapacity < 1: " + initialCapacity);
}
elements = newElementArray(initialCapacity);
this.comparator = comparator;
}
private E[] newElementArray(int capacity) {
return (E[]) new Object[capacity];
}
数组的大小,以及比较方式。
3 add方法
PriorityQueue不允许添加null元素, 利用二叉树来实现最小堆。
public boolean add(E o) {
return offer(o);
}
public boolean offer(E o) {
if (o == null) {
throw new NullPointerException("o == null");
}
growToSize(size + 1); // 是否需要扩容
elements[size] = o;
siftUp(size++); // 利用二叉树调整最小堆
return true;
}
private void growToSize(int size) { // 扩容为原来的2倍
if (size > elements.length) {
E[] newElements = newElementArray(size * DEFAULT_CAPACITY_RATIO);
System.arraycopy(elements, 0, newElements, 0, elements.length);
elements = newElements;
}
}
private void siftUp(int childIndex) {
E target = elements[childIndex];
int parentIndex;
while (childIndex > 0) {
parentIndex = (childIndex - 1) / 2;
E parent = elements[parentIndex];
if (compare(parent, target) <= 0) {
break;
}
elements[childIndex] = parent;
childIndex = parentIndex;
}
elements[childIndex] = target;
}
4 获取方法
poll | 获取并且删除第一个(最小)元素 |
peek | 获取第一个(最小)元素 |
poll方法如下,
public E poll() {
if (isEmpty()) {
return null;
}
E result = elements[0];
removeAt(0);
return result;
}
5 删除方法
从头查找并删除第一个为o的元素
public boolean remove(Object o) {
if (o == null) {
return false;
}
for (int targetIndex = 0; targetIndex < size; targetIndex++) {
if (o.equals(elements[targetIndex])) {
removeAt(targetIndex);
return true;
}
}
return false;
}
private void removeAt(int index) {
size--;
E moved = elements[size];
elements[index] = moved;
siftDown(index);
elements[size] = null;
if (moved == elements[index]) {
siftUp(index);
}
}