前言
优先级队列是包含0个或多个元素的集合,每个元素都一个权重值,每次出队弹出优先级最大或最小的元素,优先级队列是使用堆来实现了,所以大家看之间需要首先掌握堆结构。
1、主要属性分析
queue
:存储元素的数组comparator
:比较器,在优先级队列中,每个元素都有权重值,也有两种比较元素大小的方式,一种是元素的自然顺序,一种是通过比较器来比较。modCount
:修改次数,这个属性是为了fast-fail。
2、常用构造方法分析
这里提供了多个构造方法,你可以自己指定容量大小和比较器。
3、常用方法解析
3.1、入队方法
入队方法有两个,
add
方法和offer
方法,add
方法内部也是调用offer
方法来实现的。offer
方法执行步骤如下:
- 对元素做判空校验,不能插入空元素
- 判断当前数组是否满了,如果满了就先调用
grow
方法进行扩容- 判断如果当前队列没有元素,那么就放到数组的第一个
- 如果当前队列有数据,那么调用
siftUp
方法插入到指定位置,然后做自下而上的堆化。
扩容方法,判断容量小于64那么每次扩容都是扩容2倍,当数组大于64那么每次扩容至增加一半,然后还会检查扩容后的容量有没有达到最大容量上限,有没有溢出等。
根据是否指定比较器调用不同的方法
这两个方法的区别就是在比较的是否是否使用自己指定的比较器。方法流程步骤如下:
- 这个传入的下标是当前队列的最后,首先找到父节点的位置,然后比较插入元素和父节点的值,如果小于父节点就和父节点交换位置(小顶堆),直到出现比父节点大为止。
- 两个方法的区别就是在于堆化的时候,和父节点比较的时候是采用默认比较还是指定比较器比较。
3.2、出队方法
出队有两个方法,
remove
和poll
方法,remove
也是调用的poll
方法,只是在没有元素的时候抛出异常。poll
方法步骤如下:
- 如果当前队列没有元素,则返回空
- 将队列首元素弹出,再把队列末元素移到队列首
- 调用
siftDown
方法做堆化。
这里做自上而下的堆化,根据是否有比较器调用不同的方法,这个我们已经知道内部逻辑一致,只是比较的时候是否用指定的比较器。我们看下
siftDownComparable
的方法执行流程:
- 这里因为堆是完全二叉树,所以叶子节点占了一半的元素,所以只需要比较一半就行了。
- 做自上而下堆化,一直往下与最小的子节点比较,如果比最小的字节点大,就叫唤位置,再继续与最小的子节点比较,如果比最小的子节点小,就不用交换位置了,堆化结束。
3.3、查看堆顶元素
这里队列中的第一个就是堆顶元素
4、总结
PriorityQueue
是一个小顶堆,他不是有序列表,只是通过堆化维持堆顶存储最大或最小的元素。