所在包
package java.util;
继承AbstractQueue
实现java.io.Serializable
public class PriorityQueue<E> extends AbstractQueue<E>
implements java.io.Serializable {
// 内部代码下面讲解
}
五个变量
private static final long serialVersionUID = -7720805057305804111L;
// 默认容量
private static final int DEFAULT_INITIAL_CAPACITY = 11;
/**
* 数组存储,数组存储的是堆内元素
*/
private transient Object[] queue;
/**
* 优先队列内元素个数
*/
private int size = 0;
/**
* 比较器
*/
private final Comparator super E> comparator;
/**
*修改次数
*/
private transient int modCount = 0;
构造函数
/**
* 创建一个具有默认初始容量(11),根据其自然顺序对其元素PriorityQueue。
*/
public PriorityQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
/**
* 创建与根据其自然顺序对其元素指定的初始容量创建一个PriorityQueue。
*
* @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);
}
/**
* 创建与根据指定的比较器对其元素指定的初始容量创建一个PriorityQueue。
* @throws IllegalArgumentException if {@code initialCapacity} is
* less than 1
*/
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;
}
/**
* 创建一个包含指定优先级队列中的元素一个PriorityQueue
* @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
*/
@SuppressWarnings("unchecked")
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);
}
}
/**
* 创建一个包含指定有序set的元素一个PriorityQueue。
* @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
*/
@SuppressWarnings("unchecked")
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
*/
@SuppressWarnings("unchecked")
public PriorityQueue(SortedSet extends E> c) {
this.comparator = (Comparator super E>) c.comparator();
initElementsFromCollection(c);
}
当是集合中元素加入到优先队列的时候,构造队列,加入元素,初始化优先队列
private void initFromPriorityQueue(PriorityQueue extends E> c) {
if (c.getClass() == PriorityQueue.class) {
this.queue = c.toArray(); // 该集合是优先队列,直接复制
this.size = c.size();
} else { // 不是优先队列
initFromCollection(c);
}
}
private void initElementsFromCollection(Collection extends E> c) {
Object[] a = c.toArray();
// If c.toArray incorrectly doesn't return Object[], copy it.
if (a.getClass() != Object[].class)
a = Arrays.copyOf(a, a.length, Object[].class);
int len = a.length;
if (len == 1 || this.comparator != null)
for (int i = 0; i < len; i++)
if (a[i] == null)
throw new NullPointerException();
this.queue = a;
this.size = a.length;
}
/**
* Initializes queue array with elements from the given Collection.
*
* @param c the collection
*/
private void initFromCollection(Collection extends E> c) {
initElementsFromCollection(c);
heapify();// 构建堆
}
增加容量相关操作
/**
* 容量最大值
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 增加数组容量
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
int oldCapacity = queue.length;
// Double size if small; else grow by 50%
int newCapacity = oldCapacity + ((oldCapacity < 64) ?
(oldCapacity + 2) : // 增加原始容量大小+2
(oldCapacity >> 1)); // 增加元素容量大小的一半
// overflow-conscious code
if (newCapacity - MAX_ARRAY_SIZE > 0)
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;
}
插入、删除、查看等操作
/**
* 加入元素
* @throws NullPointerException if the specified element is null
*/
public boolean add(E e) {
return offer(e);
}
/**
* 具体加入元素操作
* @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);
size = i + 1;
if (i == 0)
queue[0] = e;
else
siftUp(i, e); // i 位置加入元素 e
return true;
}
// 参看队顶元素,也就是数组第一个元素
public E peek() {
if (size == 0)
return null;
return (E) queue[0];
}
// o 元素的下标
private int indexOf(Object o) {
if (o != null) {
for (int i = 0; i < size; i++)
if (o.equals(queue[i]))
return i;
}
return -1;
}
/**
* 删除元素 o
*
* @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); // 找到元素 o 的下标
if (i == -1)
return false;
else {
removeAt(i); // 删除操作
return true;
}
}
/**
*
* 根据相同引用删除,iteration.remove 需要用到
* @param o element to be removed from this queue, if present
* @return {@code true} if removed
*/
boolean removeEq(Object o) {
for (int i = 0; i < size; i++) {
if (o == queue[i]) {
removeAt(i);
return true;
}
}
return false;
}
/**
* 删除 i 位置元素,删除其中一个位置的元素后,需要调整堆
* 下面是用最后一个位置元素替代 i 位置的元素后,进行调整堆 关于调整堆的先不考虑
*/
private E removeAt(int i) {
assert i >= 0 && i < size;
modCount++;
int s = --size;
if (s == i) // removed last element
queue[i] = null;
else {
E moved = (E) queue[s];
queue[s] = null;
siftDown(i, moved);
if (queue[i] == moved) {
siftUp(i, moved);
if (queue[i] != moved)
return moved;
}
}
return null;
}
/**
* 是否包含元素 o
* @param o object to be checked for containment in this queue
* @return {@code true} if this queue contains the specified element
*/
public boolean contains(Object o) {
return indexOf(o) != -1;
}
返回数组形式
/**
* 队列转换为数组
*
* @return an array containing all of the elements in this queue
*/
public Object[] toArray() {
return Arrays.copyOf(queue, size);
}
/**
* 队列元素更改数组a中元素
* @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[] toArray(T[] a) {
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;
}
迭代器相关操作
/**
* 获取迭代器
* @return an iterator over the elements in this queue
*/
public Iterator iterator() {
return new Itr();
}
private final class Itr implements Iterator<E> {
/**
* 下一个位置索引
*/
private int cursor = 0;
/**
* 最近调用的元素索引,
* unless that element came from the forgetMeNot list.
* Set to -1 if element is deleted by a call to remove.
*/
private int lastRet = -1;
/**
* A queue of elements that were moved from the unvisited portion of
* the heap into the visited portion as a result of "unlucky" element
* removals during the iteration. (Unlucky element removals are those
* that require a siftup instead of a siftdown.) We must visit all of
* the elements in this list to complete the iteration. We do this
* after we've completed the "normal" iteration.
*
* We expect that most iterations, even those involving removals,
* will not need to store elements in this field.
*/
private ArrayDeque forgetMeNot = null;
/**
* Element returned by the most recent call to next iff that
* element was drawn from the forgetMeNot list.
*/
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 {
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;
}
}
大小、出队、清空
public int size() {
return size;
}
/**
* 清空
*/
public void clear() {
modCount++;
for (int i = 0; i < size; i++)
queue[i] = null;
size = 0;
}
// 出队列
public E poll() {
if (size == 0)
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);
return result;
}
构建满足比较器的堆
堆的构建是从下向上插入节点的过程
当i节点的左右孩子节点都是堆的时候,第i位置插入了节点x,插入的这个节点可能不满足堆的性质,这个时候需要比较其和两个孩子的值,当不符合所要求的堆时候,交换该孩子和x节点值,交换后可能孩子节点不满足堆了,这样是一个循环的过程了
/**
* k 位置插入 节点 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);
else
siftDownComparable(k, x);
}
private void siftDownComparable(int k, E x) {
Comparable super E> key = (Comparable super E>)x;
int half = size >>> 1; // loop while a non-leaf
while (k < half) { // half - size 部分是叶子节点,所有这个是个循环的k的最大值
int child = (k << 1) + 1; // left 孩子
Object c = queue[child];
int right = child + 1; // right 孩子
if (right < size &&
((Comparable super E>) c).compareTo((E) queue[right]) > 0) // left right 比较
c = queue[child = right]; // 更新后的值,或者不更新
if (key.compareTo((E) c) <= 0) // 和父节点 x 比较 ,true 不需要交换,结束
break;
queue[k] = c; // k 位置 设为 c 节点
k = child; // 循环进行
}
queue[k] = key;
}
// 同上
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;
}
构建初始堆的过程
由于size/2 – size 部分在堆的叶子节点部分,所有已经是堆,不用调整
private void heapify() {
for (int i = (size >>> 1) - 1; i >= 0; i--)
siftDown(i, (E) queue[i]);
}
下面函数在堆中加入元素时候用到了
这是一个已经是堆的数组,在**尾部**k处加入了一个新的元素
这个时候可能不是堆了,需要调整
由于在尾部加入,该位置没有孩子节点
所有只需要和其父亲节点进行比较
比较和父节点的值,是否满足堆的性质,满足不交换,否则进行交换
这个交换一直到根节点,对于数组而言也就是数组下标为0的位置
如果是中间节点的值改变了,可能出现需要调整k位置孩子节点的问题,下面程序就需要修改了
/**
* @param k the position to fill
* @param x the item to insert
*/
private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}
// k 位置元素 用 x 替代
private void siftUpComparable(int k, E x) {
Comparable super E> key = (Comparable super E>) x;
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (key.compareTo((E) e) >= 0)
break;
queue[k] = e;
k = parent;
}
queue[k] = key;
}
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;
}
获取比较器
public Comparator super E> comparator() {
return comparator;
}
输入流、输出流
/**
* Saves the state of the instance to a stream (that
* is, serializes it).
*
* @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.
* @param s the stream
*/
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".
for (int i = 0; i < size; i++)
s.writeObject(queue[i]);
}
/**
* Reconstitutes the {@code PriorityQueue} instance from a stream
* (that is, deserializes it).
*
* @param s the stream
*/
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();
queue = new Object[size];
// Read in all elements.
for (int i = 0; i < size; i++)
queue[i] = s.readObject();
// Elements are guaranteed to be in "proper order", but the
// spec has never explained what that might be.
heapify();
}