概述
阅读 Java 版本为 1.8.0.25。
PriorityQueue 即优先队列,也是一个非常重要的队列实现形式,通过堆实现。
优先队列的作用是能保证每次取出的元素都是队列中权值最小的(Java的优先队列每次取最小元素)。这里牵涉到了大小关系,元素大小的评判可以通过元素本身的自然顺序(natural ordering),也可以通过构造时传入的比较器(Comparator)。
然后说下,在排序算法中,有一个高效并且消耗内存少的排序方法 – 堆排序。堆排序算法应该是网上到处都是,可以自行百度。
还是和以前一样,将 PriorityQueue 源码以及相关类拷贝至自定义包内,进行注释添加,代码请移步:
https://github.com/qianwei4712/JDK1.8.0.25-read/blob/master/src/main/java/java/util/PriorityQueue.java
知识点总结如下:
堆的简单介绍
堆有2个概念:第一个是内存里面的堆,也就是静态链表;第二个堆是数据结构里的 二叉堆BinaryHeap,JDK 里表现为 PriorityQueue 优先队列 。
Java 中 PriorityQueue 通过堆实现,具体说是通过完全二叉树(complete binary tree)实现的小顶堆 ,然后是最小堆的定义:
- 是一个完全二叉树
- 任意节点的值小于等于左右两个孩子的值(如果有)
- 任意非叶子节点的左右子树也都是堆
堆的下标关系:
- 根节点下标为0
- 若节点 P 的下标为 i,则左孩子为 2i+1,右孩子为 2i+2
- 若节点 P 的下标为 i,则父节点的下标为 (i-1)/2
堆是一个典型的,用物理上线性表示逻辑上非线性的数据结构 ,例如下面这个例子的下标排列顺序
PriorityQueue构造方法
PriorityQueue 底层字段如下,经有4个字段,底层基于数组实现。
modCount 字段在 ArrayList 中做了详细解释,原本是 AbstractList 的 protected 字段。不过 PriorityQueue 没继承,就定义了一个,用于线程不安全情况下的快速失败判断机制。
//底层使用数组实现
transient Object[] queue; // 非私有以简化嵌套类访问
//优先队列元素个数
private int size = 0;
//优先队列比较器,如果为null,优先队列使用元素的自然顺序。
private final Comparator<? super E> comparator;
//修改次数,fast-fail机制,因为没有继承 AbstractList,所以需要自行定义。
transient int modCount = 0;
PriorityQueue 静态常量如下:
//默认初始容量
private static final int DEFAULT_INITIAL_CAPACITY = 11;
//数组最大容量,实际值为2^31-1-8,超出会爆OutOfMemoryError。
//数组除了存放数据外,还有一个length属性,减8为了存放数组长度
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
PriorityQueue 的构造方法是我目前知道的最多的,有7个构造方法。。
因为 PriorityQueue 我基本没用过。。只能凭个人感觉哪些构造方法比较重要贴下了。
//无参构造器,默认数组长度 11;无比较器,元素按照顺序排序
public PriorityQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
//指定长度,没有比较器的构造函数,元素按照顺序排序
public PriorityQueue(int initialCapacity) {
this(initialCapacity, null);
}
//创建一个带有比较器的优先队列,其元素根据比较器进行排序。默认长度 11
public PriorityQueue(Comparator<? super E> comparator) {
this(DEFAULT_INITIAL_CAPACITY, comparator);
}
//指定初始化长度和比较器的构造器,其元素根据比较器进行排序
public PriorityQueue(int initialCapacity, Comparator<? super E> comparator) {
//如果参数长度是 1,抛出异常。。
if (initialCapacity < 1)
throw