Java8 PriorityQueue 源码解析

PriorityQueue 优先级队列

前世今生

extends AbstractQueue
AbstractQueue extends AbstractCollection implements Queue

实现原理大白话

内部使用你所熟悉的数据结构最堆来实现,每次都是取堆顶的元素。至于堆怎么实现,其实很简单,就一个数组而已,这里就不讨论怎么实现堆了。默认是根据传入的对象进行比较建立初始堆的。比如说 String 实现了 Comparable 接口,里面就是根据这个进行排序建立初始堆的。

主要的构造函数
// 可以使用外排序 Comparator 来构建你自己的堆,默认为空
// initialCapacity 为初始堆大小,一般来说,为了避免扩容,或者空间浪费,我们要选择合适的值,默认值为 DEFAULT_INITIAL_CAPACITY = 11
public PriorityQueue(int initialCapacity, Comparator<? super E> comparator)

常用的方法

添加元素
public boolean add(E e) {
        return offer(e);
    }
// 调用的是offer
public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        // 几乎所有的集合类都有这个,顾名思义,主要是记录修改次数,实际上是为了防止你在遍历的时候更改了数据,造成不一致,会抛出ConcurrentModificationException 异常,注意,这与并发没有多大联系
        modCount++;
        int i = size;
        // 检查是否需要扩容,queue就是真实数据
        if (i >= queue.length)
            grow(i + 1);
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
            // 使用经典的 siftUp 上移最后添加的元素, 保证我们的堆还是有序的
            siftUp(i, e);
        return true;
    }
删除元素
// 同样使用 siftDown,首先将最后一个元素移到堆顶,再调整堆即可
public E poll() {
        if (size == 0)
            return null;
        int s = --size;
        modCount++;
        E result = (E) queue[0];
        E x = (E) queue[s];
        queue[s] = null;
        if (s != 0)
            siftDown(0, x);
        return result;
    }
获取堆顶元素
// 直接数组返回
// 也可以使用 element(),是 abstractQueue 的方法,调用的也是 peek() 再一次感受到多态对象的强大
public E peek() {
        return (size == 0) ? null : (E) queue[0];
    }
获取后一位置的元素
// 因为使用的是最堆的数据结构,所以只能遍历,效率较低
private int indexOf(Object o) {
        if (o != null) {
            for (int i = 0; i < size; i++)
                if (o.equals(queue[i]))
                    return i;
        }
        return -1;
    }
关于siftUp
// 如果没有外排序,则使用内排序
private void siftUp(int k, E x) {
        if (comparator != null)
            siftUpUsingComparator(k, x);
        else
            siftUpComparable(k, x);
    }
简单看一个函数,复习一下堆
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;
    }
你可能遇到的坑
如果你中途改变了数据,有关排序的字段,最小堆是不会自动重新构建,那么,这个优先级队列就会失效!!!!!!举个例子,你把一堆学生按身高放入优先级队列,突然,有几个学生的身高改变了,这个最小堆是不会重构的,这时候得不到你想要的值,那有没有重构的函数,抱歉,没有!heapify 是私有的函数,但是你可以通过 new PriorityQueue(queue),重新构建一个
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值