PriorityQueue
基于动态数组实现最小堆(完全二叉树)的优先级队列
目录
PriorityQueue继承关系
PriorityQueue实现了Serializable接口,支持序列化,可通过序列化传输
PriorityQueue有SuppressWarnings注解,编译器忽略指定的警告
PriorityQueue继承了AbstractQueue抽象类,执行队列的操作
PriorityQueue源码解析
私有不可变 迭代器类Itr:
private final class Itr implements Iterator<E> {
/**
* 下一次调用next返回的元素索引
*/
private int cursor;
/**
* 最后一次调用next返回的元素索引
* 若通过remove删除, 则置为-1
*/
private int lastRet = -1;
/**
* 用于记录在迭代过程中, 由于被移除而进入到堆的已访问部分但是却需要迭代的元素
* 需访问这个列表中的所有元素来完成迭代
*
* We expect that most iterations, even those involving removals,
* will not need to store elements in this field.
*/
private ArrayDeque<E> forgetMeNot;
/**
* 最近一次调用next返回的元素
*/
private E lastRetElt;
/**
* The modCount value that the iterator believes that the backing
* Queue should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
private int expectedModCount = modCount;
Itr() {} // prevent access constructor creation
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++]; // 这次返回元素的索引lastRet = cursor, 下次返回元素的索引 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 {
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;
}
}
不可变 可分割迭代器PriorityQueueSpliterator:
final class PriorityQueueSpliterator implements Spliterator<E> {
private int index; // current index, modified on advance/split
private int fence; // -1 until first use
private int expectedModCount; // initialized when fence set
/** Creates new spliterator covering the given range. */
PriorityQueueSpliterator(int origin, int fence, int expectedModCount) {
this.index = origin;
this.fence = fence;
this.expectedModCount = expectedModCount;
}
private int getFence() { // initialize fence to size on first use
int hi;
if ((hi = fence) < 0) {
expectedModCount = modCount;
hi = fence = size;
}
return hi;
}
public PriorityQueueSpliterator trySplit() {
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
return (lo >= mid) ? null :
new PriorityQueueSpliterator(lo, index = mid, expectedModCount);
}
public void forEachRemaining(Consumer<? super E> action) {
if (action == null)
throw new NullPointerException();
if (fence < 0) { fence = size; expectedModCount = modCount; }
final Object[] es = queue;
int i, hi; E e;
for (i = index, index = hi = fence; i < hi; i++) {
if ((e = (E) es[i]) == null)
break; // must be CME
action.accept(e);
}
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
public boolean tryAdvance(Consumer<? super E> action) {
if (action == null)
throw new NullPointerException();
if (fence < 0) { fence = size; expectedModCount = modCount; }
int i;
if ((i = index) < fence) {
index = i + 1;
E e;
if ((e = (E) queue[i]) == null
|| modCount != expectedModCount)
throw new ConcurrentModificationException();
action.accept(e);
return true;
}
return false;
}
public long estimateSize() {
return getFence() - index;
}
public int characteristics() {
return Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.NONNULL;
}
}
PriorityQueue构造方法:
/**
* 创建一个初始容量=11的优先级队列
* 根据元素自然顺序排序
*/
public PriorityQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
/**
* 创建一个指定初始容量的优先级队列
* 根据元素自然顺序排序
*
* @param initialCapacity the initial capacity for this priority queue
* @throws IllegalArgumentException if {@code initialCapacity} is less
* than 1
*/
public PriorityQueue(int initialCapacity) {
this(initialCapacity, null);
}
/**
* 创建一个初始容量=11的优先级队列
* 元素根据指定的比较器进行排序
*
* @param comparator 用于排序此队列的比较器, 如果为null, 将根据元素自然顺序排序
* @since 1.8
*/
public PriorityQueue(Comparator<? super E> comparator) {
this(DEFAULT_INITIAL_CAPACITY, comparator);
}
/**
* 创建一个指定初始容量的优先级队列
* 元素根据指定的比较器进行排序
*
* @param initialCapacity the initial capacity for this priority queue
* @param comparator 用于排序此队列的比较器, 如果为null, 将根据元素自然顺序排序
* @throws IllegalArgumentException if {@code initialCapacity} is
* less than 1
*/
public PriorityQueue(int initialCapacity,
Comparator<? super E> comparator) {
// 实际不需要至少一个的限制, 为了保持1.5兼容性, 该限制仍在继续
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.queue = new Object[initialCapacity];
this.comparator = comparator;
}
/**
* 创建一个包含指定元素的优先级队列
* 如果指定的集合是SortSet/PriorityQueue实例, 则队列根据相同顺序排序
* 否则根据元素自然顺序排序
*
* @param c the collection whose elements are to be placed
* into this priority queue
* @throws ClassCastException if elements of the specified collection
* cannot be compared to one another according to the priority
* queue's ordering
* @throws NullPointerException if the specified collection or any
* of its elements are null
*/
public PriorityQueue(Collection<? extends E> c) {
if (c instanceof SortedSet<?>) {
SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
this.comparator = (Comparator<? super E>) ss.comparator();
initElementsFromCollection(ss); // 将集合的元素复制到队列中
}
else if (c instanceof PriorityQueue<?>) {
PriorityQueue<? extends E> pq = (PriorityQueue<? extends E>) c;
this.comparator = (Comparator<? super E>) pq.comparator();
initFromPriorityQueue(pq); // 将优先级队列的元素复制到队列中
}
else {
this.comparator = null;
initFromCollection(c); // 使用给定集合中的元素初始化队列
}
}
/**
* Creates a {@code PriorityQueue} containing the elements in the
* specified priority queue. This priority queue will be
* ordered according to the same ordering as the given priority
* queue.
*
* @param c the priority queue whose elements are to be placed
* into this priority queue
* @throws ClassCastException if elements of {@code c} cannot be
* compared to one another according to {@code c}'s
* ordering
* @throws NullPointerException if the specified priority queue or any
* of its elements are null
*/
public PriorityQueue(PriorityQueue<? extends E> c) {
this.comparator = (Comparator<? super E>) c.comparator();
initFromPriorityQueue(c);
}
/**
* Creates a {@code PriorityQueue} containing the elements in the
* specified sorted set. This priority queue will be ordered
* according to the same ordering as the given sorted set.
*
* @param c the sorted set whose elements are to be placed
* into this priority queue
* @throws ClassCastException if elements of the specified sorted
* set cannot be compared to one another according to the
* sorted set's ordering
* @throws NullPointerException if the specified sorted set or any
* of its elements are null
*/
public PriorityQueue(SortedSet<? extends E> c) {
this.comparator = (Comparator<? super E>) c.comparator();
initElementsFromCollection(c);
}
/**
* 将集合的元素复制到队列中
*/
private void initElementsFromCollection(Collection<? extends E> c) {
Object[] es = c.toArray();
int len = es.length;
// If c.toArray incorrectly doesn't return Object[], copy it.
if (es.getClass() != Object[].class)
es = Arrays.copyOf(es, len, Object[].class); // c.toArray()返回的不是Object[], 通过复制转成Object[]
if (len == 1 || this.comparator != null)
for (Object e : es) // 检查元素中有无null
if (e == null)
throw new NullPointerException();
this.queue = ensureNonEmpty(es);
this.size = len;
}
/**
* 将指定优先级队列的元素复制到队列中
*/
private void initFromPriorityQueue(PriorityQueue<? extends E> c) {
if (c.getClass() == PriorityQueue.class) {
this.queue = ensureNonEmpty(c.toArray()); // 转换为数组
this.size = c.size();
} else {
initFromCollection(c); // 使用给定集合中的元素初始化队列
}
}
/**
* 确保queue[0]存在, 来帮助peek()和poll()
*/
private static Object[] ensureNonEmpty(Object[] es) {
return (es.length > 0) ? es : new Object[1];
}
/**
* 使用给定集合中的元素初始化队列
*
* @param c the collection
*/
private void initFromCollection(Collection<? extends E> c) {
initElementsFromCollection(c); // 将集合的元素复制到队列中
heapify(); // 建堆
}
PriorityQueue增删方法:
/**
* 数组扩容
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
int oldCapacity = queue.length;
// newCapacity = oldCapacity < 64 ? 2*oldCapacity + 2 : 1.5*oldCapacity
int newCapacity = oldCapacity + ((oldCapacity < 64) ?
(oldCapacity + 2) :
(oldCapacity >> 1));
// overflow-conscious code
if (newCapacity - MAX_ARRAY_SIZE > 0)
// 所需最小容量 > 指定最大的数组容量:使用Integer.MAX_VALUE
newCapacity = hugeCapacity(minCapacity);
queue = Arrays.copyOf(queue, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
/**
* 指定的元素插入优先级队列
*
* @return {@code true} (as specified by {@link Collection#add})
* @throws ClassCastException if the specified element cannot be
* compared with elements currently in this priority queue
* according to the priority queue's ordering
* @throws NullPointerException if the specified element is null
*/
public boolean add(E e) {
return offer(e);
}
/**
* 指定的元素插入优先级队列
*
* @return {@code true} (as specified by {@link Queue#offer})
* @throws ClassCastException if the specified element cannot be
* compared with elements currently in this priority queue
* according to the priority queue's ordering
* @throws NullPointerException if the specified element is null
*/
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
grow(i + 1);
siftUp(i, e); // 在i位置插入元素e, 然后进行堆排序
size = i + 1;
return true;
}
/**
* 查询队列头部元素
*/
public E peek() {
return (E) queue[0];
}
/**
* 根据元素返回索引
*/
private int indexOf(Object o) {
if (o != null) {
final Object[] es = queue;
for (int i = 0, n = size; i < n; i++)
if (o.equals(es[i]))
return i;
}
return -1;
}
/**
* 如果存在元素e, 使得o.equals(e), 则删除他
*
* @param o element to be removed from this queue, if present
* @return {@code true} if this queue changed as a result of the call
*/
public boolean remove(Object o) {
int i = indexOf(o);
if (i == -1)
return false;
else {
removeAt(i); // 根据索引删除元素
return true;
}
}
/**
* 根据元素删除与哦哟
*
* @param o element to be removed from this queue, if present
*/
void removeEq(Object o) {
final Object[] es = queue;
for (int i = 0, n = size; i < n; i++) {
if (o == es[i]) {
removeAt(i); // 根据索引删除元素
break;
}
}
}
/**
* Removes all of the elements from this priority queue.
* The queue will be empty after this call returns.
*/
public void clear() {
modCount++;
final Object[] es = queue;
for (int i = 0, n = size; i < n; i++)
es[i] = null;
size = 0;
}
/**
* 抛出es[0]元素
* 然后最小堆排序
*/
public E poll() {
final Object[] es;
final E result;
if ((result = (E) ((es = queue)[0])) != null) {
modCount++;
final int n;
final E x = (E) es[(n = --size)];
es[n] = null;
if (n > 0) {
final Comparator<? super E> cmp;
if ((cmp = comparator) == null)
siftDownComparable(0, x, es, n);
else
siftDownUsingComparator(0, x, es, n, cmp);
}
}
return result;
}
/**
* 从队列中删除第i个元素。
*
* Normally this method leaves the elements at up to i-1,
* inclusive, untouched. Under these circumstances, it returns
* null. Occasionally, in order to maintain the heap invariant,
* it must swap a later element of the list with one earlier than
* i. Under these circumstances, this method returns the element
* that was previously at the end of the list and is now at some
* position before i. This fact is used by iterator.remove so as to
* avoid missing traversing elements.
*/
E removeAt(int i) {
// assert i >= 0 && i < size;
final Object[] es = queue;
modCount++;
int s = --size;
if (s == i) // removed last element
es[i] = null;
else {
E moved = (E) es[s];
es[s] = null;
siftDown(i, moved); // 向下排序(跟子节点比较)
if (es[i] == moved) {
siftUp(i, moved); // 向上排序(跟父节点比较)
if (es[i] != moved)
return moved;
}
}
return null;
}
/**
* 删除满足表达式条件得元素
*
* @throws NullPointerException {@inheritDoc}
*/
public boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
return bulkRemove(filter);
}
/**
* 删除包含在指定集合中得元素
*
* @throws NullPointerException {@inheritDoc}
*/
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
return bulkRemove(e -> c.contains(e));
}
/**
* 删除未包含在指定集合中得元素
*
* @throws NullPointerException {@inheritDoc}
*/
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return bulkRemove(e -> !c.contains(e));
}
/**
* 批量删除元素
*/
private boolean bulkRemove(Predicate<? super E> filter) {
final int expectedModCount = ++modCount;
final Object[] es = queue;
final int end = size;
int i;
// Optimize for initial run of survivors
for (i = 0; i < end && !filter.test((E) es[i]); i++)
;
if (i >= end) {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
return false;
}
// Tolerate predicates that reentrantly access the collection for
// read (but writers still get CME), so traverse once to find
// elements to delete, a second pass to physically expunge.
final int beg = i;
final long[] deathRow = nBits(end - beg);
deathRow[0] = 1L; // set bit 0
for (i = beg + 1; i < end; i++)
if (filter.test((E) es[i]))
setBit(deathRow, i - beg);
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
int w = beg;
for (i = beg; i < end; i++)
if (isClear(deathRow, i - beg))
es[w++] = es[i];
for (i = size = w; i < end; i++)
es[i] = null;
heapify();
return true;
}
PriorityQueue堆排序方法:
/**
* 在整个树中建立堆不变式, 不假设调用之前元素的顺序
* Floyd.1964提出的经典算法称为O(size)
*/
private void heapify() {
final Object[] es = queue;
int n = size, i = (n >>> 1) - 1; // i = n / 2 - 1 (n >>> 1:二进制右移)
final Comparator<? super E> cmp;
if ((cmp = comparator) == null)
for (; i >= 0; i--) // 总共需移动 n/2-1 次?
// 类实现了Comparable接口
siftDownComparable(i, (E) es[i], es, n);
else
for (; i >= 0; i--)
// Comparator比较器
siftDownUsingComparator(i, (E) es[i], es, n, cmp);
}
/**
* 在位置k插入项x,
* 通过反复将x降级直到其小于或等于其子级或为叶,
* 从而保持堆不变
*
* @param k the position to fill
* @param x the item to insert
*/
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x, queue, size, comparator);
else
siftDownComparable(k, x, queue, size);
}
/**
* 使用Comparable接口调整堆, 数组下标从0开始
*/
private static <T> void siftDownComparable(int k, T x, Object[] es, int n) {
// assert n > 0;
// key = x = es[k], 记录根节点值(基于es[k]作为根节点的子树)
Comparable<? super T> key = (Comparable<? super T>)x;
int half = n >>> 1; // 一半大小
while (k < half) {
int child = (k << 1) + 1; // es[k]的左子节点下标child
Object c = es[child]; // es[child] = 左子节点值
int right = child + 1; // es[k]的右子节点下标right
// 若es[child] > es[right] 则 es[child] = es[right] 且 child = right
if (right < n &&
((Comparable<? super T>) c).compareTo((T) es[right]) > 0)
c = es[child = right];
// 若 根节点的值 key <= 子节点的值es[child] 则结束循环
if (key.compareTo((T) c) <= 0)
break;
es[k] = c; // 否则 key > es[child]:子节点值es[child] 上移到 根节点值es[k]
k = child; // k = child , es[k] = es[child], 满足条件则以child为父节点进行下一次循环,否则:k记录了根节点的位置
}
es[k] = key; // 将根节点值放入es[k]中
}
/**
* 使用Comparator比较器调整堆
*/
private static <T> void siftDownUsingComparator(
int k, T x, Object[] es, int n, Comparator<? super T> cmp) {
// assert n > 0;
int half = n >>> 1;
while (k < half) {
int child = (k << 1) + 1;
Object c = es[child];
int right = child + 1;
if (right < n && cmp.compare((T) c, (T) es[right]) > 0)
c = es[child = right];
if (cmp.compare(x, (T) c) <= 0)
break;
es[k] = c;
k = child;
}
es[k] = x;
}
/**
* 在位置k插入元素x
* 通过将x提升到树的上方直到其 >= 其父级或成为根, 从而保持堆不变
*
* To simplify and speed up coercions and comparisons, the
* Comparable and Comparator versions are separated into different
* methods that are otherwise identical. (Similarly for siftDown.)
*
* @param k the position to fill
* @param x the item to insert
*/
private void siftUp(int k, E x) {
if (comparator != null)
// Comparator比较器
siftUpUsingComparator(k, x, queue, comparator);
else
// 类实现了Comparable接口
siftUpComparable(k, x, queue);
}
/**
* 使用Comparable接口调整堆
*/
private static <T> void siftUpComparable(int k, T x, Object[] es) {
Comparable<? super T> key = (Comparable<? super T>) x; // key = x = es[k]
while (k > 0) {
int parent = (k - 1) >>> 1; // k 的父节点:parent = (k-1)/2
Object e = es[parent];
if (key.compareTo((T) e) >= 0) // 若 es[k] >= es[parent], 满足最小堆, 结束
break;
es[k] = e; // 否则:将父节点的值替换子节点的值
k = parent; // 索引k指向父节点, 进行下一次的向上比较
}
es[k] = key; // 最终初始子节点的值赋给es[k]
}
/**
* 使用Comparator比较器调整堆
*/
private static <T> void siftUpUsingComparator(
int k, T x, Object[] es, Comparator<? super T> cmp) {
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = es[parent];
if (cmp.compare(x, (T) e) >= 0)
break;
es[k] = e;
k = parent;
}
es[k] = x;
}
PriorityQueue转换数组方法:
/**
* 返回一个包含队列中所有元素的数组, 没有特定顺序
*
* <p>The returned array will be "safe" in that no references to it are
* maintained by this queue. (In other words, this method must allocate
* a new array). The caller is thus free to modify the returned array.
*
* <p>This method acts as bridge between array-based and collection-based
* APIs.
*
* @return an array containing all of the elements in this queue
*/
public Object[] toArray() {
return Arrays.copyOf(queue, size);
}
/**
* 返回一个包含队列中所有元素的数组
* 返回的数组的运行时类型是指定数组的运行时类型
* 返回的数组元素没有特定的顺序
* 如果队列小于指定的数组大小则将其返回
* 否则将使用指定数组的运行时类型和此队列的大小分配一个新数组
*
* 如果指定的数组有多余的空间, 其余元素设置为null
*
* <p>Like the {@link #toArray()} method, this method acts as bridge between
* array-based and collection-based APIs. Further, this method allows
* precise control over the runtime type of the output array, and may,
* under certain circumstances, be used to save allocation costs.
*
* <p>Suppose {@code x} is a queue known to contain only strings.
* The following code can be used to dump the queue into a newly
* allocated array of {@code String}:
*
* <pre> {@code String[] y = x.toArray(new String[0]);}</pre>
*
* Note that {@code toArray(new Object[0])} is identical in function to
* {@code toArray()}.
*
* @param a the array into which the elements of the queue are to
* be stored, if it is big enough; otherwise, a new array of the
* same runtime type is allocated for this purpose.
* @return an array containing all of the elements in this queue
* @throws ArrayStoreException if the runtime type of the specified array
* is not a supertype of the runtime type of every element in
* this queue
* @throws NullPointerException if the specified array is null
*/
public <T> T[] toArray(T[] a) {
final int size = this.size;
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(queue, size, a.getClass());
System.arraycopy(queue, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
PriorityQueue序列化方法:
/**
* Saves this queue to a stream (that is, serializes it).
*
* @param s the stream
* @throws java.io.IOException if an I/O error occurs
* @serialData The length of the array backing the instance is
* emitted (int), followed by all of its elements
* (each an {@code Object}) in the proper order.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out element count, and any hidden stuff
s.defaultWriteObject();
// Write out array length, for compatibility with 1.5 version
s.writeInt(Math.max(2, size + 1));
// Write out all elements in the "proper order".
final Object[] es = queue;
for (int i = 0, n = size; i < n; i++)
s.writeObject(es[i]);
}
/**
* Reconstitutes the {@code PriorityQueue} instance from a stream
* (that is, deserializes it).
*
* @param s the stream
* @throws ClassNotFoundException if the class of a serialized object
* could not be found
* @throws java.io.IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in (and discard) array length
s.readInt();
SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size);
final Object[] es = queue = new Object[Math.max(size, 1)];
// Read in all elements.
for (int i = 0, n = size; i < n; i++)
es[i] = s.readObject();
// Elements are guaranteed to be in "proper order", but the
// spec has never explained what that might be.
heapify();
}
PriorityQueue总结
PriorityQueue使用动态数组实现最小堆(完全二叉树),根节点是队列中最小的元素。
PriorityQueue无论何时调用remove方法,都会返回队列中最小的元素。
遍历PriorityQueue时,没有任何顺序保证。
PriorityQueue是线程不安全的,无同步策略。
PriorityQueue不允许插入null元素。