1.堆的介绍:
(1)堆逻辑上是一棵完全二叉树;
(2)堆物理上是保存在数组中;
(3)满足任意节点的值都大于其子树中节点的值——大根堆,大堆 或者最大堆
(4) 相反,则是小根堆,小堆,或者最小堆。
2.根据数组序列创建小根堆过程分析:
分析:
(1)index(代表要调整位置的下标) 如果已经是叶子节点,则整个调整过程结束;
- 判断index 位置是否有孩子节点;
- 只对其判断是否有左孩子;因为堆是完全二叉树,即没有左孩子就一定没有右孩子;
- 判断是否有左孩子即判断左孩子下标是否越界,即left >= size(数组长度)越界;
(2)确定index 节点的左右孩子的最小值min;
- 若右孩子不存在;则 min = left;
- 否则,比较array[left] 和array[right]的值,选择小的为min;
(3)比较array[index] 的值 和 array[min] 的值,如果 array[index] <= array[min];z则满足小堆的性质,调整结束;
(4)否则,交换array[index] 和 array[min] 的值;
(5)因min位置可能破坏了堆的性质,将min看做index向下重复此过程;
3.数组序列创建大根堆的实现:
public class HeapTest {
public int[] elem;
public int usedSize;
public HeapTest() {
this.elem = new int[10];
}
//1)创建大根堆
public void createBigHeap(int[] array){
for(int i = 0;i < array.length;i++){
this.elem[i] = array[i];
this.usedSize ++;
}
//此时elem[]中已经存放了元素
for(int i = (this.usedSize - 1 - 1 )/2;i >= 0;i--){
adjustDown(i,usedSize);
}
}
//2)向下调整
public void adjustDown(int parent,int len){
int child = 2 * parent + 1;
while(child < len){
//child + 1 < len 判断当前是否 有右孩子
if(child + 1 < len && this.elem[child] < this.elem[child + 1]){
child++;
}
//此时child 下标 一定是 左右孩子的最大值下标
if(this.elem[parent] < this.elem[child]){
int tmp = this.elem[parent];
this.elem[parent] = this.elem[child];
this.elem[child] = tmp;
parent = child;
child = 2 * parent + 1;
}else{
//因为是从最后一棵树开始调整的,
// 当this.elem[parent] > this.elem[child]
//后续就不需要循环了,后面的都已经是大根堆了
break;
}
}
}
public void show(){
for (int i = 0; i <this.usedSize; i++) {
System.out.print(this.elem[i] + " ");
}
System.out.println();
}
}
运行结果: