PriorityQueue 源码

PriorityQueue

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;
}
复制代码

上浮图片

siftup.png

offer 向堆中添加元素 向上比较

public boolean offer(E e) {
    if (e == null)
        throw new NullPointerException();
    modCount++;
    int i = size;
    // 扩容
    if (i >= queue.length)
        grow(i + 1);
    // 数量+1
    size = i + 1;
    if (i == 0)
        queue[0] = e;
    else
    // 下标的位置i e 
        siftUp(i, e);
    return true;
}
复制代码

siftUp 向上比较

private void siftUp(int k, E x) {
    if (comparator != null)
        siftUpUsingComparator(k, x);
    else
        siftUpComparable(k, x);
}
复制代码

siftUpComparable 构建最小堆

private void siftUpComparable(int k, E x) 
{
    // 梳理逻辑 每次加入一个元素 都要向上比较 然后 重新构建一个最小堆
    Comparable<? super E> key = (Comparable<? super E>) x;
    // k=0 的时候到达了根节点
    while (k > 0) 
    {
        int parent = (k - 1) >>> 1;
        // 父元素的值
        Object e = queue[parent];
        // 当添加的值比父元素大的时候 退出循环  
        if (key.compareTo((E) e) >= 0)
            //添加的值
            break;
        // 当添加的值比父元素小的时候  把父元素的值对调到传入值的位置
        // 
        queue[k] = e;
        k = parent;
    }
    // 传入的x 最终放的位置
    queue[k] = key;
}
复制代码

poll 取出队列中的队首数据 删除元素

public E poll() {
    if (size == 0)
        return null;
    int s = --size;
    modCount++;
    // 1、取到队列中的第一个元素
    E result = (E) queue[0];
    // 2、取到最后一个元素
    E x = (E) queue[s];
    //3、GC 清空数据
    queue[s] = null
    // 4、往下比较
    if (s != 0)
        siftDown(0, x);
        // 返回队首元素
    return result;
}
复制代码

siftDown 下沉 k=0 | x 最后一个元素

private void siftDown(int k, E x) {
    if (comparator != null)
        siftDownUsingComparator(k, x);
    else
        siftDownComparable(k, x);
}
复制代码

siftDownComparable(k, x); k=0 | 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) 
    {
        // 1、左孩子节点index  默认左节点最小值
        int child = (k << 1) + 1; 
        // 2、左孩子节点值
        Object c = queue[child];
        // 3、右孩子节点值
        int right = child + 1;
        // 比较左右节点的最大值 取到最小值index
        if (right < size &&
            // 如果左边>右边  表示右节点是最小值节点 不是默认的左节点
            ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
            // 
            c = queue[child = right];
        // 再次比较根节点的值 也就是传入的x 和孩子节点中的最小值做比较  如果小于的话 退出循环 
        // 已经是最小堆了
        if (key.compareTo((E) c) <= 0)
            break;
        // 也就是父节点的值比孩子节点中的最小值要大 不符合最小堆 继续调整
        queue[k] = c;
        k = child;
    }
    queue[k] = key;
}
复制代码

下沉图片

siftdown.png

heapify 将一个无序数组构造成最小堆

private void heapify() 
{
    /**int i = (size >>> 1) - 1,
      这行代码是为了找寻最后一个非叶子节点,然后倒序进行"下移"siftDown操作
     */
    for (int i = (size >>> 1) - 1; i >= 0; i--)
        // i 数组下标 queue[i] 要下沉的值
        siftDown(i, (E) queue[i]);
}
复制代码

heapify图形结合

图片.png

图片.png

图片.png

图片.png 我们观察下用数组a建成的二叉堆,很明显,对于叶子节点4、15、11、1、3来说,它们已经是一个合法的堆。所以只要最后一个节点的父节点,也就是最后一个非叶子节点a[4]=10开始调整,然后依次调整a[3]=12,a[2]=5,a[1]=6,a[0]=7,分别对这几个节点做一次"下移"操作就可以完成了堆的构造。ok,我们还是用图解来分析下这个过程。

假设有一个无序的数组,要求我们将这个数组建成一个二叉堆,你会怎么做呢?最简单的办法当然是将数组的数据一个个取出来,调用入队方法。但是这样做,每次入队都有可能会伴随着元素的移动,这么做是十分低效的。那么有没有更加高效的方法呢,我们来看下。

猜你喜欢

转载自juejin.im/post/7035821487109963783
今日推荐