priorityQueue 是一个堆 (heap) 的数据结构,底层就是一个数组,逻辑上是一棵完全二叉树。并且PQ的堆顶idx 是0。也就是说 对于任意的节点,
x
x
, , 这里算法的算法设计和本科数据结构教材相同,我们重点看,这几个算法,siftUP,siftDown,heapify
private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}
@SuppressWarnings("unchecked")
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;
}
@SuppressWarnings("unchecked")
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)// 当前元素大于等于父亲 ok
break;
queue[k] = e;
k = parent;
}
queue[k] = x;
}
/**
* Inserts item x at position k, maintaining heap invariant by
* demoting x down the tree repeatedly until it is less than or
* equal to its children or is a leaf.
*
* @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);
}
@SuppressWarnings("unchecked")
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) {
int child = (k << 1) + 1; // assume left child is least
Object c = queue[child];
int right = child + 1;
if (right < size &&
((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
c = queue[child = right];
if (key.compareTo((E) c) <= 0)
break;
queue[k] = c;
k = child;
}
queue[k] = key;
}
@SuppressWarnings("unchecked")
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)// 选择孩子中最小的那个和当前元素(k,E) 比较
c = queue[child = right];
if (comparator.compare(x, (E) c) <= 0)// x <= child ,ok满足性质
break;
queue[k] = c;
k = child;
}
queue[k] = x;
}
/**
* Establishes the heap invariant (described above) in the entire tree,
* assuming nothing about the order of the elements prior to the call.
*/
@SuppressWarnings("unchecked")
private void heapify() {
for (int i = (size >>> 1) - 1; i >= 0; i--)
siftDown(i, (E) queue[i]);
}
siftUp(int idx,E e)
的意思是假设 节点 e
当前在 idx
将他不破坏堆的性质,向上滑动,我们可以看见里面分提供comparator 和comparable 对象提供了封装方法。其他就没什么好说的了,任何一本数据结构书籍都会讲的。注意这里直接从已知集合构造堆的时间复杂度是
O(n)
O
(
n
)
, 原因在这个 heapify
方法,他从最后一个非叶子节点开始逐个向下滑动,对于一颗完全二叉树来说,这样的移动次数不会超过
O(n)
O
(
n
)
, 这个是很好证明的,假设完全二叉树共
n
n
个节点, 层,第
i
i
层元素为 ,则最多需要移动
具体计算我省略了。
由于上面两个方法 siftUp,siftDown
都是
O(logN)
O
(
l
o
g
N
)
的,所以凡是仅仅和 idx
相关的操作复杂度都为 O(logN)
(e.g.: add,poll)这两个都是对一个是对最后一个元素的操作另一个是对堆顶元素的操作,都可以仅通过 siftUP
或者siftDown
完成。
不过需要注意 remove(Obj)
的复杂度是
O(n)
O
(
n
)
的,因为他要先遍历整个堆然后再删除。