PriorityQueue实现的方式和数据结构中二叉堆的基本实现是一致。也就是内置了一个数组,将这个数组视为一个树,这棵树有这样的一些特性:
- 对应任意节点i ,其左子节点为(2*i+1),右节点为2*(i+1);
- 数组的前半部分必为非叶节点。
内置了siftUp和siftDown两种私有访问的方法用于进行下滤和上移操作。其次还有需要注意的是对指定comparator的应用。其他的部分比较常规。
初始化
如上图所示,C表示构造函数,绿色表示public访问,红色表示private访问,灰色是辅助标注。
一般来说初始化包括两大类,一类是非集合参数的初始化。
非集合类:
最终调用的都是PriorityQueue(int i,Comparator < ? extends E >)。默认参数分别是11和null;
集合类:
集合类的调用构造器对结果进行了分类,最终都会使用3中方式完成初始化。这里主要来看下这三种方式:
- initElementsFromCollection
private void initElementsFromCollection(Collection<? extends E> c) {
Object[] a = c.toArray();
// If c.toArray incorrectly doesn't return Object[], copy it.
if (a.getClass() != Object[].class)
a = Arrays.copyOf(a, a.length, Object[].class);
int len = a.length;
if (len == 1 || this.comparator != null)
for (int i = 0; i < len; i++)
if (a[i] == null)
throw new NullPointerException();
this.queue = a;
this.size = a.length;
}
这个类新建了一个Object[]类型的数组,将内部的queue指向这个新建的Object数组。这里不太明白的是既然是检测元素是否为非0 为何要在if (len == 1 || this.comparator != null
这样的情况下检测。而不是所有情况下都检测。首先comparator!=null。比较好理解一些,因为如果是null的话那后续调用null.comparator必然会出现问题。但是len==1就不是很明白了。
在输入序列是一个sortSet的情况下。只需要将其数组直接赋值过来就行。其实这个比较好理解。因为堆自身实际上并不是全排序的而是偏序的,而一个排序的集合生成的数组必然满足堆的内置数组的排序要求。或者说全排序的数组是堆的数组的一种特殊情况。因此直接复制就可以了。
- initFromCollection
private