【jdk1.8】PriorityQueue源码分析

#优先级队列内部维护了一个堆的数据结构

1. 成员变量

    /**
     *  底层维护一个数组,其中queue[n]的左右两个孩子分别是
     *  queue[2*n+1]和queue[2*(n+1)](因为是从零开始的)。
     *  最高优先级即比较后最小的元素在队首queue[0]。
     */
    transient Object[] queue; 

    /**
     * 优先级队列中元素的个数。
     */
    private int size = 0;

    /**
     * 用来比较优先级的比较器。若为空,则采用元素的自然顺序。
     * 比如数字的大小和字符串的字典序等。
     */
    private final Comparator<? super E> comparator;

    /**
     * 优先级队列结构修改的次数。
     * 主要用于iterator来判断是否并发修改而需要抛出
     * ConcurrentModificationException异常。
     */
    transient int modCount = 0;


2. 入队方法

1. public boolean offer(E e)

    public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        //修改次数增加
        modCount++;
        //新增元素在该位置
        int i = size;
        //如果越界,则需要扩容
        //如果容量比较小(阈值64)则加倍,否则加50%。
        if (i >= queue.length)
            grow(i + 1);
        //元素个数增加
        size = i + 1;
        //队列为空
        if (i == 0)
            queue[0] = e;
        //元素加在末尾而向上调整
        else
            siftUp(i, e);
        return true;
    }

2.private void siftUp(int k, E x)

    private void siftUp(int k, E x) {
    	//使用比较器
        if (comparator != null)
            siftUpUsingComparator(k, x);
    	//如果没有比较器则使用自然序
        else
            siftUpComparable(k, x);
    }

    @SuppressWarnings("unchecked")
    private void siftUpComparable(int k, E x) {
    	//key是即将要插入的数据
        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)//大于等于0应该往后排,即优先级低
                break;
            //如果优先级比双亲节点高,双亲节点往后排
            queue[k] = e;
            //往上调整,双亲的位置成了当前位置
            k = parent;
        }
        //将待插入的元素插入到合适位置
        queue[k] = key;
    }

3. 出队方法

1. public E poll()

    @SuppressWarnings("unchecked")
    public E poll() {
    	//队列为空返回null
        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;
    }

2. private void siftDown(int k, E x)

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

    @SuppressWarnings("unchecked")
    private void siftDownComparable(int k, E x) {
    	//key为待调整元素
        Comparable<? super E> key = (Comparable<? super E>)x;
        //一半的地方
        int half = size >>> 1;        // loop while a non-leaf
        //当非叶节点,循环
        while (k < half) {
        	//待调整孩子序号,默认左孩子序号
            int child = (k << 1) + 1; // assume left child is least
            //待调整孩子,默认左孩子
            Object c = queue[child];
            //右孩子序号
            int right = child + 1;
            //如果右孩子存在,且右孩子优先级高
            if (right < size &&
                ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
            	//应该与右孩子的位置调整
                c = queue[child = right];
            //如果待调整元素优先级高,则说明已经找到了合适的位置
            if (key.compareTo((E) c) <= 0)
                break;
            //如果key优先级低,那么c应该往前面交换
            queue[k] = c;
            //孩子节点变成当前节点,即往下调整
            k = child;
        }
        //将待调整的元素插入到合适的位置
        queue[k] = key;
    }

4. 移除指定位置元素的方法

    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);
            /**此一情况偶尔出现,出现在调用iterator.remove的时候*/
            //当调整完之后还位于待删除的地方,则说明队尾元素的优先级可能还要更高
            if (queue[i] == moved) {
            	//向上调整
                siftUp(i, moved);
                //如果上浮了,返回队尾元素
                if (queue[i] != moved)
                    return moved;
            }
        }
        //其他情况返回空
        return null;
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值