堆排序可以分为两个部分:一是构造大(小)根堆,二是下沉排序。
一、堆的构造
堆:是一棵顺序存储的完全二叉树。
大(小)根堆:所有节点值都不大(小)于父节点的值。
从上图中可以看出堆中父节点与子节点的关系为:Num(lchild) = Num(parent) * 2 +1
Num(rchild) = Num(parent) * 2 +2
下面通过图形展示大根堆的构造过程:
对于数组{16,7,3,20,17,8}
1.堆初始状态: 按数组顺序依次构造完全二叉树
2.从二叉树的最右非叶子节点(array.length / 2)开始调整,如下图所示:
3.节点值20与节点值16互换后,发现节点值16的子节点中有更大值的节点,则互换得到最终结果
第一次调整结束。
二、下沉排序
将最右叶子节点与根节点互换,然后3作为根节点不满足大根堆的性质,需要调整;循环这个过程直到得到整个有序数列。
三、下面是Java代码的具体实现
public class HeapSort {
public void sort(int[] a,int i, int n){
int parent = i;
int child = 2 * parent + 1;
int temp = a[parent];
while(child < n){
if(child + 1 < n && a[child] < a[child + 1]){
child += 1;
}
if(temp > a[child])
break;
a[parent] = a[child];
parent = child;
child = child * 2 + 1;
}
a[parent] = temp;
}
public void heapSort(int[] a, int n){
for(int i = n / 2;i >= 0;i-- ){
sort(a, i, n-1);
}
for(int j = n -1;j > 0;j--){
int temp = a[j];
a[j] = a[0];
a[0] = temp;
sort(a, 0, j);
for(int k = 0; k < n; k++){
System.out.print(a[k]+" ");
}
System.out.println();
}
}
public static void main(String[] args) {
int a[] = {16,7,3,20,17,8};
HeapSort s = new HeapSort();
s.heapSort(a, a.length);
}
}