堆排序笔记

堆排序笔记

堆排序学习网站

一开始直接看别人写的堆排序,感觉不能理解,后来看了这个视频网站,就好理解了。
视频链接:http://www.iqiyi.com/v_19rrhzzs1k.html

堆排序的实现与笔记

做个笔记,方便以后自己回顾。

public class 第四次实现堆排序 {

    public static void main(String[] args) {
        int[] array = {2,4,235,23,6,3,7,34,5,7,457};
        sortHeap(array);
        print(array);
    }

    /**
     * 调整堆——要实现升序的话,需要构建的是大顶堆
     * @param a 数组
     * @param s 父节点下标
     * @param length 有效长度,即参与调整的数组部分(这里没理解好,在sortHeap方法调用该方法的时候就会出问题)
     */
    public static void adjustHeap(int[] a, int s, int length){
        int temp;
        temp = a[s];                //当执行完这一步,下标s对应的位置就相当于一个空的位置
        for(int j=2*s;j<length;j=2*j){  //因为length表示的是数组的有效长度,而j表示的是数组下标,因此要j一定要小于length
            if(j<length-1 && a[j]<a[j+1])   //这里我觉得是j<length-1而不是j<length
                j++;                //目的是找出较大的子节点的下标
            if(temp>=a[j])          //如果父节点就是比较大的子节点还大,那就无需调整了,跳出循环
                break;
            a[s] = a[j];            //否则就将较大的那个子节点的数据放到父节点中(最开始的父节点中的数据已经存储在temp中了),如此下标j指向的位置就成了空位置
            s = j;                  //让下标s指向新的空位置
        }
        a[s] = temp;                //最后把temp中存储的父节点元素存到空位置上
    }

    public static void sortHeap(int[] a){
        /*
         * 理解好,堆在逻辑结构上是一颗完全二叉树,但是在物理结构上是用数组来表示
         * 因此,没有填充堆这一操作,因为我们是用数组来表示,因此,本身就已经填充好了
         * 我们要做的,是调整,使之成为一个大顶堆,然后再执行堆排序
         */
        //如何调整堆,使之成为大顶堆?从逻辑结构上看,堆是一个完全二叉树,我们从最后一个非叶子节点开始调整(叶子节点无需调整),一直往前,对每个非叶子节点进行遍历,从而生成一个大顶堆
        int length = a.length;
        for(int i=(length-1)/2;i>=0;i--)
            adjustHeap(a,i,length);     //(很重要!!)根据adjustHeap方法参数的理解,最后一个参数代表有效长度,因此这里是写length而不是length-1!!!!!
        //堆排序
        for(int j=length-1;j>0;j--){
            //把堆顶元素换到最后
            swap(a,0,j);
            //调整堆
            adjustHeap(a,0,j);      //(很重要!!)最后一个参数是j还是j-1?按照adjustHeap方法参数的理解是有效长度!!那么应该是j才对!
        }
    }

    //交换方法
    public static void swap(int[] c,int a,int b){
        int temp = c[a];
        c[a] = c[b];
        c[b] = temp;
    }

    //打印方法
    public static void print(int[] a){
        for(int i:a)
            System.out.print(i+" ");
    }
}

/*
 * 对堆排序的理解:
 * 堆排序,就是排序算法的一种。要求是使用数组,而不能是链表。也没有说是树结构。
 * 我们使用堆排序的思想就是利用完全二叉树的结构,也就是说我们建造的堆就是一个完全二叉树结构,这是逻辑上的结构,但其物理结构则是用数组来表示完全二叉树的。
 */

/*
 * 堆排序适合于数据量非常大的场合(百万数据)。 
 * 堆排序不需要大量的递归或者多维的暂存数组。这对于数据量非常巨大的序列是合适的。
 * 比如超过数百万条记录,因为快速排序,归并排序都使用递归来设计算法,在数据量非常大的时候,可能会发生堆栈溢出错误。 
 * 堆排序会将所有的数据建成一个堆,最大的数据在堆顶,然后将堆顶数据和序列的最后一个数据交换。
 * 接下来再次重建堆,交换数据,依次下去,就可以排序所有的数据。
 */

时间复杂度

每次调整heap中k个元素重新建立堆的时间复杂度与堆的高度有关,为O(logk),又需要对n个元素进行调整,时间复杂度为O(n),因此总的时间复杂度为O(nlogk)。堆排序在最好、最差、平均情况下的时间复杂度都为O(nlogk)。

拓展链接

堆排序的应用场景:http://blog.csdn.net/shakespeare001/article/details/51360732

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值