1、并非按FIFO进出
传统的queue 是按先进先出的顺序执行。而PriorityQueue是按优先级来绝对的
优先级低的先出queue
2、如何排序
PriorityQueue既然有优先级排序 那么如何排序的。
a. 放入队列的元素实现了Comparable接口 按其自然顺序排序 从小到大。
b. 初始化队列时指明Comparator外部比较器。
PriorityQueue<String> queue1 = new PriorityQueue<>();
PriorityQueue<String> queue2 = new PriorityQueue<>(10);
PriorityQueue<String> queue3 = new PriorityQueue<>((a,b)->a.compareTo(b));
3、内部结构
内部使用数组存放元素:
transient Object[] queue;
数组默认容量11 (初始化时可以指定)
动态扩容机制
容量<64 扩容为2*n+2,否则跟ArrayList一样扩大为1.5n
(64是一个权衡的不大不小的值)
private void grow(int minCapacity) {
int oldCapacity = queue.length;
// Double size if small; else grow by 50%
int newCapacity = oldCapacity + ((oldCapacity < 64) ?
(oldCapacity + 2) :
(oldCapacity >> 1));
// overflow-conscious code
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
queue = Arrays.copyOf(queue, newCapacity);
}
小根堆实现
小根堆:是一种完全二叉树 且满足父节点不大于任意一个左右子节点。(注意左右节点是没有顺序的)
所以小根堆的顶点必然是最小的 (如何要实现从大到小排序,指定的Comparator中取相反顺序即可)
而完全二叉树(所有节点满足从左到右排列 不会垮节点)是可以用数组表示的。
PriorityQueue就是使用数组来实现的小根堆: 满足每次取的数据都是最小的,但不满足整体都是有序的。
任意一个节点(数组中索引为n) 都可以知道其左右子节点和父节点在数组中的索引值:
父节点 : (n-1)/2
左子节点: 2n+1
右子节点:2n+2
关于节点的增删
增:在完全二叉树中依次创建一个新节点,再把新节点跟父节点依次比较,使其满足最小堆要求
删:删除的节点 用二叉树的最后一个节点先填充,再进行调整。
总是都是拿最有的节点处理,因为要满足完全二叉树。
具体细节网上例子很多 不再详解。
4、非线程安全
PriorityQueue的线程安全版本:PriorityBlockingQueue,使用ReentrantLock加锁保护