PriorityBlockingQueue优先队列的二叉堆实现

转载请注明原创地址http://www.cnblogs.com/dongxiao-yang/p/6293807.html

  

   java.util.concurrent.PriorityBlockingQueue内部用二叉堆实现了一个优先队列,所有插入的元素必须实现java.lang.Comparable接口。由于完全二叉树可以用数组来表示,所以队列内部元素存放在可变长度数组queue里。

 

private transient Object[] queue; //用于存放元素的数组

 

一 插入元素入队

 

    public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        final ReentrantLock lock = this.lock;
        lock.lock();
        int n, cap;
        Object[] array;
        while ((n = size) >= (cap = (array = queue).length))
            tryGrow(array, cap);
        try {
            Comparator<? super E> cmp = comparator;
            if (cmp == null)
                siftUpComparable(n, e, array);
            else
                siftUpUsingComparator(n, e, array, cmp);
            size = n + 1;
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
        return true;
    } 


//新元素堆内上浮实现

private static <T> void siftUpComparable(int k, T x, Object[] array) { Comparable<? super T> key = (Comparable<? super T>) x; //尝试转化插入对象为Comparable实例 while (k > 0) { int parent = (k - 1) >>> 1; // 新元素x的数组下标为k,对应的父节点的下标为(k-1)/2 Object e = array[parent]; if (key.compareTo((T) e) >= 0) //如果子节点已经比父节点还要大,不需要再跟上层节点比较,新元素上浮结束 break; array[k] = e; //如果子节点已经比父节点小,父节点下沉,新元素上浮一次 k = parent; //新元素上浮后继续与新的父节点比较大小,直到k=0或者新的父节点小于新元素 } array[k] = key;//新元素在堆中插入正确的位置。 }

一 弹出元素出队

    public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return dequeue();
        } finally {
            lock.unlock();
        }
    }

    private E dequeue() {
        int n = size - 1;
        if (n < 0)
            return null;
        else {
            Object[] array = queue;
            E result = (E) array[0];
            E x = (E) array[n];
            array[n] = null;
            Comparator<? super E> cmp = comparator;
            if (cmp == null)
                siftDownComparable(0, x, array, n);//堆顶的最小值被弹出了,堆顶变成了空节点,空节点开始下浮到合适位置后用数组最后子节点填充。
            else
                siftDownUsingComparator(0, x, array, n, cmp);
            size = n;
            return result;
        }
    }
//空元素堆内下沉实现
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 half最后一个有子节点的父节点下标 while (k < half) { 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 = child; //空节点下滑到最小子节点的位置 } array[k] = key; // 最后空节点填充数组最后的值 } }

参考资料:数据结构之优先队列--二叉堆(Java实现) 

原文地址:https://www.cnblogs.com/dongxiao-yang/p/6293807.html