目录
概念:
前面介绍过队列,队列是一种先进先出(FIFO)的数据结构,但有些情况下,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素先出队列。在这种情况下,数据结构就提供了两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(PriorityQueue)。
堆:
堆实际就是在完全二叉树的基础上进行了一些元素的调整。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆的性质:
- 堆中某个节点的值总是不大于或不小于其父节点的值;
- 堆总是一棵完全二叉树。
堆的存储方式:
从堆的概念可知,堆是一棵完全二叉树,存储的时候,是以数组的形式进行存储的,数组当中的数据,都是以层序遍历的方式存储的。
堆的创建:
首先我们要知道:已知孩子结点下标 i,父亲结点的下标为:(i-1)/2;已知父亲结点下标i,左孩子的下标为:2*i + 1 ,右孩子的下标为 2*i + 2 。
以小堆为例(向下调整)
文字描述:
1. 让parent标记需要调整的节点,child标记parent的左孩子(注意:parent如果有孩子一定先是有左孩子)
2. 如果parent的左孩子存在,即:child < size,进行以下操作,直到parent的左孩子不存在
3. 看parent右孩子是否存在,存在找到左右孩子中最小的孩子
4. 让child进行标注将parent与较小的孩子child比较,如果:parent小于较小的孩子child,调整结束否则:交换parent与较小的孩子child
5. 交换完成之后,parent中大的元素向下移动,可能导致子树不满足堆的性质,因此需要继续向下调整,即parent = child;child = parent*2+1; 然后继续从2开始执行。
图解:
以27为根的左右子树都满足小堆的性质,只有根结点不满足,因此只用调整根结点的位置,就能得到一个小堆
代码:
publicvoidshiftDown(int[]array,intparent){
//child先标记parent的左孩子,因为parent可能右左没有右
int child=2*parent+1;
int size=array.length;
while(child<size){
//如果右孩子存在,找到左右孩子中较小的孩子,用child进行标记
if(child+1<size&&array[child+1]<array[child]){
child+=1;
}
//如果双亲比其最小的孩子还小,说明该结构已经满足堆的特性了
if(array[parent]<=array[child]){
break;
}else{
//将双亲与较小的孩子交换
int=array[parent];
array[parent]=array[child];
array[child]=t;
//parent中大的元素往下移动,可能会造成子树不满足堆的性质,因此需要继续向下调整
parent=child;child=parent*2+1;
}
}
}
堆的插入与删除:
堆的插入:
堆的插入总共需要两个步骤:
1. 先将元素放入到底层空间中(注意:空间不够时需要扩容)
2. 将最后新插入的节点向上调整,直到满足堆的性质
堆的删除:
1. 将堆顶元素对堆中最后一个元素交换
2. 将堆中有效数据个数减少一个
3. 对堆顶元素进行向下调整