先知道PriorityBlockingQueue 是利用数组存储二叉堆实现。最小值(最优先)放在queue[0]位置。
//删除某个元素
public boolean remove(Object o) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
int i = indexOf(o);//先找到元素的位置,见下面函数源码
if (i == -1)
return false;
removeAt(i);//根据元素位置删除数据,见下面函数源码
return true;
} finally {
lock.unlock();
}
}
//获取某个元素数组的下标
private int indexOf(Object o) {
if (o != null) {
Object[] array = queue;
int n = size;
for (int i = 0; i < n; i++)
if (o.equals(array[i]))
return i;
}
return -1;
}
//根据下标去删除数据
private void removeAt(int i) {
Object[] array = queue;
int n = size - 1;
if (n == i) // removed last element
array[i] = null;
else {
E moved = (E) array[n];//保存最后一个元素
array[n] = null;//最后一个元素赋值null
Comparator<? super E> cmp = comparator;
if (cmp == null)
siftDownComparable(i, moved, array, n);//以自实现Comparable接口对象为例(其实是把最后一个元素放到被删除元素的位置,让后通过,不断降级的算法,再构造合法的堆结构),见下面函数源码
else
siftDownUsingComparator(i, moved, array, n, cmp);
if (array[i] == moved) {
if (cmp == null)
siftUpComparable(i, moved, array);
else
siftUpUsingComparator(i, moved, array, cmp);
}
}
size = n;
}
/**
* 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.
* 把x 元素放在 下标k的位置。通过循环降级x的位置(如果有必要),直到保证x小于等于它的任何子节点,以维持堆的结构合法性。
* @param k the position to fill
* @param x the item to insert
* @param array the heap array
* @param n heap size
*/
private static <T> void siftDownComparable(int k, T x, Object[] array,
int n) {
if (n > 0) {
Comparable<? super T> key = (Comparable<? super T>)x;
int half = n >>> 1; // loop while a non-leaf 当是非叶子节点位置,才循环。
while (k < half) {//这个意思就是,如果k位置有子节点,那么k的位置一定在数组前半部分。因为在数组中,一个元素位置为k那么它的左节点在2k+1位置,右节点在2k+2位置。
int child = (k << 1) + 1; // assume left child is least
Object c = array[child];
int right = child + 1;//右孩子下标
if (right < n &&
((Comparable<? super T>) c).compareTo((T) array[right]) > 0)//如果右孩子小于左孩子
c = array[child = right];//获取右孩子
//上面语句其实是选择左右孩子较小的一个(值和位置),写法我学习了!!
if (key.compareTo((T) c) <= 0)//如果插入值比左孩子/右孩子(较小的一个)小,就是符合二叉堆,结束循环,
break;
array[k] = c;//把左孩子/右孩子(较小的一个)赋值到k位置
k = child;//把左孩子/右孩子(较小的一个)的位置赋值给k,找他们的左右孩子,下轮循环。
}
array[k] = key;//赋值插入值到k位置
}
}