基于优先堆的无界优先队列,非线程安全。
1)add、offer、remove、poll的时间复杂度为O(log(n));remove(Object)、contains(Object)为线性时间;peek、element、size为固定时间;
2)迭代器fail-fast。
基于数组的平衡二叉堆:
// queue[n]元素的两个children为queue[2*n+1]、queue[2*(n+1)]
// queue[n]<=queue[2*n+1]且queue[n]<=queue[2*(n+1)]
// queue[0]为最小值
private transient Object[] queue;
// 无参构造,初始容量为DEFAULT_INITIAL_CAPACITY=11,采用元素自然排序
public PriorityQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
// 带初始容量参数构造
public PriorityQueue(int initialCapacity) {
this(initialCapacity, null);
}
// 带初始容量、comparator参数构造
public PriorityQueue(int initialCapacity,
Comparator super E> comparator) {
// Note: This restriction of at least one is not actually needed,
// but continues for 1.5 compatibility
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.queue = new Object[initialCapacity];
this.comparator = comparator;
}
// 带Collection参数构造
public PriorityQueue(Collection extends E> c) {
if (c instanceof SortedSet>) { // SortedSets是特殊的平衡二叉堆,但需要稍调整,转化为Object[],元素不能为null
SortedSet extends E> ss = (SortedSet extends E>) c;
this.comparator = (Comparator super E>) ss.comparator();
initElementsFromCollection(ss);
}
else if (c instanceof PriorityQueue>) { // PriorityQueue参数,直接拿来用
PriorityQueue extends E> pq = (PriorityQueue extends E>) c;
this.comparator = (Comparator super E>) pq.comparator();
initFromPriorityQueue(pq);
}
else { // 对普通的Collection,转化为Object[],元素不能为null,还要对其heapify
this.comparator = null;
initFromCollection(c);
}
}
// 带PriorityQueue参数构造
public PriorityQueue(PriorityQueue extends E> c) {
this.comparator = (Comparator super E>) c.comparator();
initFromPriorityQueue(c);
}
// 带SortedSet参数构造
public PriorityQueue(SortedSet extends E> c) {
this.comparator = (Comparator super E>) c.comparator();
initElementsFromCollection(c);
}
步骤:
1)当queue已满,若有元素入队请求,则进行容量扩展;
2)oldCapacity小于64则容量翻倍;否则增长50%;
3)检查newCapacity是否在MAX_ARRAY_SIZE范围内,若minCapacity有overflow,抛出OutOfMemoryError异常;否则容量最大不超过Integer.MAX_VALUE;
4)创建新容量的Object[],将旧的queue元素复制过来。
// 当queue已满时,则进行容量扩展
if (i >= queue.length)
grow(i + 1);
private void grow(int minCapacity) {
int oldCapacity = queue.length;
// oldCapacity小于64则容量翻倍;否则增长50%
int newCapacity = oldCapacity + ((oldCapacity < 64) ?
(oldCapacity + 2) :
(oldCapacity >> 1));
// newCapacity都超过了MAX_ARRAY_SIZE,检查minCapacity是否有溢出
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
queue = Arrays.copyOf(queue, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow,抛出OutOfMemoryError异常
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? // 最大不能超过Integer.MAX_VALUE
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
// 对元素x,从k往前移,保持二叉堆的平衡性
private void siftUpUsingComparator(int k, E x) {
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (comparator.compare(x, (E) e) >= 0)
break;
queue[k] = e;
k = parent;
}
queue[k] = x;
}
// 对元素x,从k往后移,保持二叉堆的平衡性
private void siftDownUsingComparator(int k, E x) {
int half = size >>> 1;
while (k < half) {
int child = (k << 1) + 1;
Object c = queue[child];
int right = child + 1;
if (right < size &&
comparator.compare((E) c, (E) queue[right]) > 0)
c = queue[child = right];
if (comparator.compare(x, (E) c) <= 0)
break;
queue[k] = c;
k = child;
}
queue[k] = x;
}
步骤:
1)检查队列是否已满,若满则进行容量扩展;
2)从队尾,对元素进行siftUp,保持二叉堆的平衡性;
3)返回true
// 因无容量限制,add委托给offer
public boolean add(E e) {
return offer(e);
}
// 将元素入队
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
grow(i + 1);
size = i + 1;
if (i == 0) // 队列为空
queue[0] = e;
else
siftUp(i, e); // 从对尾,对元素进行siftUp
return true;
}
步骤:
1)检查队列是否为空,为空则返回null;
2)取出队列最后一个元素,从索引0开始,对其进行siftDown,保持二叉堆的平衡性;
3)返回队首元素值。
// 将队首元素出队
public E poll() {
if (size == 0) // 队列为空,返回null
return null;
int s = --size;
modCount++;
E result = (E) queue[0];
E x = (E) queue[s]; // 取出队列最后一个元素
queue[s] = null;
if (s != 0)
siftDown(0, x); // 从0开始,对最后一个元素进行siftDown
return result;
}
// Collection方法,删除内部元素
public boolean remove(Object o) {
int i = indexOf(o); // 确定索引位置
if (i == -1)
return false;
else {
removeAt(i); // 删除该元素
return true;
}
}
// 删除索引i的元素
private E removeAt(int i) {
assert i >= 0 && i < size;
modCount++;
int s = --size;
if (s == i) // 若删除的索引i元素为最后一个元素,直接赋为null
queue[i] = null;
else {
E moved = (E) queue[s]; // 取出队列最后一个元素
queue[s] = null;
siftDown(i, moved); // 从索引i开始,对最后一个元素进行siftDown
if (queue[i] == moved) { // 若取出的最后一个元素比i+1及其后的元素都小
siftUp(i, moved); // 对取出的最后一个元素,从索引i开始,进行siftUp
if (queue[i] != moved)
return moved;
}
}
return null;
}
步骤:
1)检查队列是否为空,为空则返回null;
2)返回队首元素值。
public E peek() {
if (size == 0)
return null;
return (E) queue[0];
}
不保证元素的迭代顺序:
private final class Itr implements Iterator {
private int cursor = 0;
private int lastRet = -1;
// 某些元素因为删除,为了保持二叉堆的平衡性,更换到遍历过的索引位置
// 为了确保都遍历到,这里缓存下
private ArrayDeque forgetMeNot = null;
private E lastRetElt = null;
private int expectedModCount = modCount;
public boolean hasNext() {
return cursor < size ||
(forgetMeNot != null && !forgetMeNot.isEmpty());
}
public E next() {
if (expectedModCount != modCount)
throw new ConcurrentModificationException();
if (cursor < size)
return (E) queue[lastRet = cursor++];
if (forgetMeNot != null) {
lastRet = -1;
lastRetElt = forgetMeNot.poll();
if (lastRetElt != null)
return lastRetElt;
}
throw new NoSuchElementException();
}
public void remove() {
if (expectedModCount != modCount)
throw new ConcurrentModificationException();
if (lastRet != -1) {
E moved = PriorityQueue.this.removeAt(lastRet);
lastRet = -1;
if (moved == null)
cursor--;
else { // moved不为null,说明最后一个元素更换到了遍历前的位置
if (forgetMeNot == null)
forgetMeNot = new ArrayDeque<>();
forgetMeNot.add(moved);
}
} else if (lastRetElt != null) {
PriorityQueue.this.removeEq(lastRetElt);
lastRetElt = null;
} else {
throw new IllegalStateException();
}
expectedModCount = modCount;
}
}
用平衡二叉堆的性质保证优先。