堆排序其实不难
堆是一种特殊的数据结构,它是一种完全二叉树。所以它可以用数组来很容易的表示。
堆分为大顶堆和小顶堆。
- 大顶堆: 所有节点满足:父节点的值大于孩子节点的值
- 小顶堆 与大顶堆相反
对于节点i,它的左节点left为 (i<<1)+1;右节点right为left + 1;
堆还有一个性质,对于长度为n的堆。第n/2 + 1,n个元素为叶子节点。
堆的调整算法,对于一个堆 它的左右子树都满足堆的性质,那么可以通过该算法让它和左右子树都满足该性质。
//length为堆的长度。它可以限制堆的长度。超出该长度将不会调整。
//构造大顶堆
public void heapify(int a[],int i,int length){
int left = (i<<1) + 1;
int right = left + 1;
int max = i;//最大值默认为根
if(left < length && a[left] > a[max]){
max = left;
}
if(right >length && a[right] > a[max]){
max = right;
}
//如果出现子节点比它大。
if(max != i){
swap(a,i,max);//你自己手动补上,我已经省略
heapify(int a,int max,length);//继续递归调用,让它的子树维持堆的特性
}
}
而叶子节点一定满足堆的性质,所以只要从第一个非叶子节点开始,自底向上开始调整便可以构造一个完整的堆。
public void makeMaxHeap(int[] a){
int length = a.length;
int start = length/2 -1;//索引从0开始,要减去1
for(int i = start;i>=0;i--){
heapify(a,i,length);
}
}
堆排序
如何对堆进行排序?可从一个大顶堆开始,让它的顶部与最后一个的元素交换,减少堆的长度后,然后调整堆的结构(交换后的最后节点会被排除在外)。每次调整就会将当前堆的最大值放在最后一位。如何反复直到根节点最小。
//a是一个构造好的大顶堆
public void heapSort(int a[]){
int end = a.length ;
while(end>1){
swap(a,0,end-1);//与最后一个元素交换
end--;
heapify(a,0,end);
}
}
代码全程手打,逻辑应该没有问题。怎么样堆排序简单吧。
参考:算法导论。(当然它全是伪代码。)
算法导论真的是神书,以前不懂的,现在看一看就懂了。