Java Priority Queue 实现中的 remove at 方法,为什么它在筛选后进行筛选?
In Java Priority Queue implementation remove at method, why it does a sift up after a sift down?
我一直在阅读Java合集API,优先队列部分,由Josh Bloch和Doug Lea两位大师的作品实现。
JavaPriorityQueue
是用数组堆实现的。
代码片段在这里,来自PriorityQueue.java
,第600行:
/**
* Removes the ith element from queue.
*
* 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.
*/
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);
//the code I am asking is below:
if (queue[i] == moved) {
siftUp(i, moved);
if (queue[i] != moved)
return moved;
}
}
return null;
}
奇怪的是,原来在堆底移动的元素应该是i
的子树中的一个大元素。 siftDown
的方法比较合理,经过一个siftDown
之后,最小的子树会被提升到i
.
的位置
问题是,如果i
没有变化,即moved在siftDown
之后还在,看来子树已经堆化了,不需要再次成为 siftUp
。
为什么 Josh 再次将他们举到顶端?
希望看过代码的朋友有所帮助!
问题是移动的项目(queue[size-1]
处的项目)可能与删除的项目不在同一子树中。考虑这个堆:
0
4 1
5 6 2 3
现在,如果您删除节点 5,您将拥有:
0
4 1
6 2 3
您将堆中的最后一个节点 3 放在 5 所在的位置:
0
4 1
3 6 2
你筛选了 3 个,但它已经是一片叶子了。它可能不合适。您必须对其进行筛选以获得:
0
3 1
4 6 2
我一直在阅读Java合集API,优先队列部分,由Josh Bloch和Doug Lea两位大师的作品实现。
JavaPriorityQueue
是用数组堆实现的。
代码片段在这里,来自PriorityQueue.java
,第600行:
/**
* Removes the ith element from queue.
*
* 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.
*/
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);
//the code I am asking is below:
if (queue[i] == moved) {
siftUp(i, moved);
if (queue[i] != moved)
return moved;
}
}
return null;
}
奇怪的是,原来在堆底移动的元素应该是i
的子树中的一个大元素。 siftDown
的方法比较合理,经过一个siftDown
之后,最小的子树会被提升到i
.
问题是,如果i
没有变化,即moved在siftDown
之后还在,看来子树已经堆化了,不需要再次成为 siftUp
。
为什么 Josh 再次将他们举到顶端?
希望看过代码的朋友有所帮助!
问题是移动的项目(queue[size-1]
处的项目)可能与删除的项目不在同一子树中。考虑这个堆:
0
4 1
5 6 2 3
现在,如果您删除节点 5,您将拥有:
0
4 1
6 2 3
您将堆中的最后一个节点 3 放在 5 所在的位置:
0
4 1
3 6 2
你筛选了 3 个,但它已经是一片叶子了。它可能不合适。您必须对其进行筛选以获得:
0
3 1
4 6 2