参考博客:www.cnblogs.com/lyw-hunnu/p…
上面这篇博文已经介绍的很详细了,就写一下实现过程中遇到的问题。
heapInsert
heapInsert:在一个已经存在的大根堆末尾追加一个元素,追加后调整其结构仍为大根堆。代码如下:
public static void heapInsert(int[] array,int index){
//追加的数已经添加到了数组的末尾,需要做的是调整该数的位置
while (array[index] > array[(index - 1)/2]) {
// 停止条件1:新增结点不再比父节点大
// 停止条件2:已经到达了整棵树的 根结点 0
swap(array, index, (index - 1) /2);
index = (index - 1)/2 ;
}
}
需要注意的是,while循环的终止条件有两个。
1.新增结点不再比父节点大。
2.已经到达了整棵树的根结点0。
但当index=0时,(0-1)/2=0,所以arr[index] arr[(index-1)/2] 相等。也就是说关于商,表达式a/b的商会向0取整,即负数向上取整,正数向下取整,类似于四舍五入。
heapify
heapify:当将大根堆的最大值 pop 出去之后,对堆结构进行调整仍为大根堆。此时大根堆的根节点显然不是最大值,需要对该元素进行下沉,heapify就是某元素的下沉操作。代码如下:
public static void heapify(int[] array, int index, int heapSize){
int left = index * 2 + 1;
while(left < heapSize){
//左右孩子之间值比较:右孩子存在且右孩子的值大于左孩子的值,largest=右,否则largest=左
int largest = left + 1 < heapSize && array[left + 1] > array[left] ? left + 1 : left;
//父与子比较
largest = array[largest] > array[index] ? largest : index;
if (largest == index) {
break;
}
swap(array, largest, index);
index = largest;
left = index * 2 + 1;
}
}
自己写感觉比上面的代码思路乱很多,还是采用上面的方法,习惯一下吧。
堆排序
有了上面的heapInsert和heapify,就可以进行堆排序了。堆排序的思路如下:
1.已知一数组array,先遍历数组,对数组中每个元素进行heapInsert操作,生成大根堆,得到size。
2.将生成的大根堆的根节点元素与末尾元素交换(因为根节点元素一定是最大值)。同时--size,把已经确定的最大值移出堆结构中。对交换到根节点位置的元素进行heapify。
2.重复2步骤直到堆结构为空。 代码如下:
public static void heapSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int i = 0; i < arr.length; i++) {
heapInsert(arr, i);
}
int size = arr.length;
swap(arr, 0, --size);
while (size > 0) {
heapify(arr, 0, size);
swap(arr, 0, --size);
}