目录
1、优先级队列
1.1 概念
对于队列而言,数据只能从队尾进,队头出,遵循着固定的先进先出原则。
而在某些特殊场景需求下,要求优先级高的元素先出队列,
在这种情况下,数据结构应该提供两个最基本的操作:
- ①:不仅能添加新对象
- ②:还能返回最高优先级对象。
这种数据结构就是优先级队列,Java也提供了PriorityQueue集合。
1.2 PriorityQueue底层结构
PriorityQueue的底层是堆这种数据结构,而堆实际就是在完全二叉树的基础上进行了一些调整,接下来,让我们来聊一聊堆到底是什么。
2、 堆
2.1 堆的概念
所有元素按完全二叉树的顺序存储方式存储在一个一维数组中。
堆分为 大根堆与小根堆。
大根堆:每个节点都大于或等于其子节点。
小根堆:每个节点都小于或等于其子节点。
2.2 堆的存储结构
我们已知堆为一棵完全二叉树,故采用顺序的方式存储在数组中。
而对于我们之前所学的二叉树,为什么没有采用顺序存储而是采用链式存储呢?
因为二叉树并非都为完全二叉树,若采用顺序存储会造成空间浪费:
因为堆采用顺序的方式进行存储,且为完全二叉树,故具有以下性质:
- 孩子节点下标为i,则其父亲节点下标为(i - 1)/2
- 父亲下标为i,则其左孩子下标为2i+1(2i+1<节点总数的情况下,否则无左孩子)
- 父亲下标为i,则其右孩子下标为2i+2(2i+2<节点总数的情况下,否则无右孩子)
3、优先级队列(堆)的模拟实现
3.1 堆的创建
向下调整算法
向下调整算法:选出其左右孩子中值较小值元素(建大堆就选较大元素,建小堆就选较小元素,这里以建小堆为例),将这个元素和根节点进行比较,若比根节点还小,就和根节点交换,交换后可能导致子树不满足堆的性质,因此需要继续向下调整。
注意:向下调整算法的使用,必须要求其左右子树必须为大根堆或者小根堆!!!
向下调整算法的时间复杂度为:O(logN),因为最坏情况是从根一路比较到叶子,比较的次数即为完全二叉树的高度次。
3.1.1 向下调整算法建完整堆
我们给出一组数据:{ 27,15,19,18,28,34,65,49,25,37 },要想将这组数据建成堆,我们可以使用向下调整法建堆。
而一组乱序数据其左右子树是不为堆的,那就需要通过向下调整算法从倒数第一个非叶子节点(下标为(数组.length-1-1)/2 )开始建堆,直到将整棵树建成堆。
建堆的时间复杂度为:O(N)!!!,
为什么不是O(N*logN)呢?这里给出解释:
注:下文中代码实现的为大堆
向下调整整体建堆代码:
/**
* 建堆整体时间复杂度:O(N)
*/
public void createHeap() {
//从倒数第一个飞非叶子节点开始建堆
int parent = (this.usedSize - 1 - 1)/2;
while (paren