深入理解PriorityQueue实现原理、及源码分析

PriorityQueue底层使用Object[]数组实现的一个最小二叉堆,来到达一个优先队列功能,是线程不安全的。它与FIFO的队列的区别在于,优先队列每次出队的元素都是优先级最高的元素。那么怎么确定哪一个元素的优先级最高呢?PriorityQueue使用二叉堆这种数据结构,用户可以自定义的Comparator来确定每次出队的元素总是队列里面最小的,而元素的大小比较方法可以由用户指定Comparator(Comparator就相当于指定优先级),接下来我们先来看看堆这种数据结构。

1.二叉堆介绍

堆数据结构的特性

  • 堆中某个节点的值总是不大于或不小于其父节点的值。

  • 堆总是一棵完全二叉树。

在堆数据结构又有很多种,而PriorityQueue使用的便是二叉堆,二叉堆是一种特殊的堆,二叉堆是一颗完全二叉树或者是近似一颗完全二叉树。

(1)二叉堆分类

二叉堆分为两种:最大堆和最小堆。PriorityQueue使用的便是最小二叉堆,根的位置元素永远是最小的。

  • 最大堆:父结点的键值总是大于或等于任何一个子节点的键值。

  • 最小堆:父结点的键值总是小于或等于任何一个子节点的键值。

(2)二叉堆结构

这里我们最小二叉堆为例,将一个二叉堆结构用一颗完全二叉树表示出来,各个元素位置如下图 :

上图就是一颗完全二叉树(二叉堆),二叉堆特点:那就是在第n层深度被填满之前,不会开始填第n+1层深度,且元素插入是从左往右填满。基于这个特点我们用数据结构来表示一个二叉堆,如下图:

PriorityQueue内部实现就是使用一个Object[]数组来表示二叉堆的,基于数组实现的二叉堆结构具有以下特点:

  • 跟节点:数组实现的二叉堆,根节点在index=0位置上。

  • 左孩子:数组n位置上的元素,其左孩子在[2n+1]位置上。

  • 右孩子:数组n位置上的元素,其右孩子在 2(n+1) 位置上。

  • 父节点:数组n位置上的元素,其父节点在 (n-1)/2 位置上。

到此二叉堆的结构就了解完了,接下来在继续看看PriorityQueue是怎么实现的?

2.PriorityQueue源码分析

(1)PriorityQueue主要结构

PriorityQueue继承了AbstractQueue抽象类,并实现了Serializable接口,AbstractQueue抽象类实现了Queue接口,对元素添加、删除等方法进行了一些通用的定义。PriorityQueue的底层存储结构相关定义如下:

public class PriorityQueue<E> extends AbstractQueue<E>
    implements java.io.Serializable {
    private static final long serialVersionUID = -7720805057305804111L;
    // 用数组实现的二叉堆: 如前面的说法一样,左右子节点位置、父节点位置、根节点位置。
    /**
     * Priority queue represented as a balanced binary heap: the two
     * children of queue[n] are queue[2*n+1] and queue[2*(n+1)].  The
     * priority queue is ordered by comparator, or by the elements'
     * natural ordering, if comparator is null: For each node n in the
     * heap and each descendant d of n, n <= d.  The element with the
     * lowest value is in queue[0], assuming the queue is nonempty.
     */
    transient Object[] queue; // non-private to simplify nested class access
    //数组默认初始化大小 
    private static final int DEFAULT_INITIAL_CAPACITY = 11;
    //队列的元素数量
    private int size = 0;
    //自定义比较器
    private final Comparator<? super E> comparator;
    //队列修改次数:修改版本
    transient int modCount = 0;
    //queue数组的最大长度,即队列的最大长度
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
}

可以看到PriorityQueue也是基于数组来实现一个二叉堆,PriorityQueue是一个有限队列,数据queue最大不能超过Integer.MAX_VALUE - 8,PriorityQueue中的优先级可以由用户指定,就是用户指定元素的Comparator比较器。

(2)PriorityQueue的构造方法

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值