写在开头
本文作为我学习 Java 集合 PriorityQueue 的一个记录与总结,如果文中有纰漏或者错误,请不吝赐教,共同进步!
PriorityQueue
一、PriorityQueue 介绍
1.1 PriorityQueue 概述
- PriorityQueue(优先队列) , 其底层的实现是**堆(heap)**这一数据结构
- PriorityQueue 维护底层数组长度的方式与 ArrayList 相同
- PriorityQueue 中元素默认按照元素的自然顺序排序,也可指定自定义的 Comparator
- PriorityQueue 中元素必须是彼此可比的且不能为 null
- PriorityQueue 是线程不安全的,在并发场景下应使用 PriorityBlockingQueue
1.2 PriorityQueue 底层数据结构
PriorityQueue 底层的数据结构是 堆(heap) , 其一般用数组来作为其实现,但是在逻辑上其更像一棵树,见下图,以数组实现的堆的特点为:设当前元素在数组中的下标为 n 则其左孩子为数组中下标为 [2n+1] 的元素,其右孩子为数组中下标为 [2(n+1)] 的元素。
此外,堆的另一个特点是父节点和子节点的关系,特别的对于 PriorityQueue 来说其默认的堆是一个小根堆,其特点为父节点的元素值大于左右俩个子节点,根节点的元素值为整个堆的最小值,其能够在插入或删除时自动维护堆的性质。具体的实现可参考《算法导论》,其中有关于堆的详细介绍,在此就不再继续深入下去了。
二、PriorityQueue 源码分析
2.1 继承类与接口实现
public class PriorityQueue<E> extends AbstractQueue<E>
implements java.io.Serializable
- 继承类
- AbstractQueue:队列的抽象类其实现了 Queue 结构,此类实现了队列的基本功能
- 接口
- Serializable 接口:使得 PriorityQueue 可序列化
2.2 成员变量
// PriorityQueue 第一次插入数据时底层数组的大小
private static final int DEFAULT_INITIAL_CAPACITY = 11;
// 底层数组
transient Object[] queue;
// PriorityQueue 的大小
private int size = 0;
// 元素顺序的比较器,若不指定则为 null,即使用元素的自然顺序进行排序
private final Comparator<? super E> comparator;
2.3 构造方法
看起来很多但基本都是对PriorityQueue(int , Comparator<? super E>)
的不同调用因此,详细介绍一下此构造方法
public PriorityQueue(int initialCapacity,
Comparator<? super E> comparator) {
// 保证初始化的数组大小至少为 1
if (initialCapacity < 1)
throw new IllegalArgumentException();
// 初始化底层数组
this.queue = new Object[initialCapacity];
// 初始化 PriorityQueue 的比较器为自定义比较器
this.comparator = comparator;
}
此构造主要做了两件事情,1)初始化底层数组并指定其大小,2)将 PriorityQueue 的比较器指定为用户定义的比较器。此次有一个可有可无的小细节,在此暂且一提,如果阅读过我之前有关 ArrayList 的文章的话会发现,虽然底层都是基于数组,如果不指定具体的初始化长度,那么 PriorityQueue 会在初始化时直接初始化对应长度的数组,而 ArrayList 则会在第一次 add 时才初始化对应长度的数组。
2.4 核心方法
PriorityQueue 也是队列因此其核心方法同队列相同即:add(), peek(), remove()
2.4.1 add() 方法
- add() 方法
public boolean add(E e) {
// 调用了 offer
return offer(e);
}
- offer() 方法
public boolean offer(E e) {
if (e == null)
// PriorityQueue 不允许 null
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
// 如果 PriorityQueue.size() 超过了底层数组则调用 grow() 方法扩容
grow(i + 1);
size = i + 1;