普林斯顿公开课 算法4-3:堆排

堆排的灵感源自于堆的数据结构。它是一种原地排序算法,不需要额外的临时数组。


基本思想


堆排的基本思想是:

  1. 先建立一个最大堆

  2. 将最大的元素移动到数组末尾,减小堆的大小,调整最大堆使其符合最大堆的性质

  3. 重复第二步,直到最大堆耗尽为止


第一个步骤建立最大堆的代码非常简单,只要对每个节点执行sink操作即可。


1
2
for ( int  k = N/ 2 ; k >=  1 ; k--)
     sink(a, k, N);


第二个步骤也很简单,代码如下:


1
2
3
4
while (N >  1 ) {
     exch(a,  1 , N--);
     sink(a,  1 , N);
}


动画


下图是堆排算法的动画:


http://www.sorting-algorithms.com/animation/50/random-initial-order/heap-sort.gif



复杂度


堆排在构建堆的过程中需要2N次比较和交换。

在排序的过程中需要NlgN次比较和交换。


堆排是一种最坏情况下复杂度为NlogN的原地排序算法,这两种特性是归并排序和快排都做不到的。 


堆排不是一种稳定的排序算法。不能很好的利用CPU缓存,因此性能一般。


下图展示了排序算法与算法特性之间的关系



代码

public class HeapSort {
    public static void sort(Comparable[] a) {
        // 需要假想数组a是从1开始编号的
        int N = a.length;
 
        // 建立最大堆
        for(int i=N/2;i>=1;i--){ // 注意,从最底层开始建立,而不是从最顶层开始建立
            sink(a, i, N);
        }
 
        // 依次取出最大元素,放在末尾
        while(N > 1) {
            exch(a, 1, N);
            N--;
            sink(a, 1, N);
        }
    }
 
    public static void sink(Comparable[] a, int k, int N) {
        // 循环直到没有子节点为止
        while(k*2 <= N) {
            int parent = k;
            int child1 = k*2;
            int child2 = child1+1;
 
            // 如果父亲比任意一个子节点要小
            if(less(a,parent,child1,N) || less(a,parent,child2,N)){
                // 选出较大的子节点
                int greater;
                if(less(a,child1,child2,N)) {
                    greater = child2;
                } else {
                    greater = child1;
                }
 
                // 将较大的节点与父节点交换
                exch(a, greater, parent);
 
                // 为下次循环做准备
                k = greater;
            } else {
                break; // 注意:不要忘记跳出循环
            }
        }
    }
 
    public static void exch(Comparable[] a, int x, int y) {
        // 将以1为起点的数组转换成以0为起点的数组
        x-=1;y-=1;
        SortUtil.exch(a, x,y);
    }
 
    public static boolean less(Comparable[] a, int x, int y, int N) {
        // 将以1为起点的数组转换成以0为起点的数组
        x-=1;y-=1;
 
        // 将null值视为无穷小
        if(x>=N) return true;
        if(y>=N) return false;
        return SortUtil.less(a[x],a[y]);
    }
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值