堆排序(heap sort)

堆排序


概述

对简单排序的一种改进
堆是具有下列性质的完全二叉树:
每个节点的值都大于或等于其左右孩子结点的值,称为大顶堆;
每个节点的值都小于或等于其左右孩子结点的值,称为小顶堆。

堆排序算法思想:

将待排序的列表,构造成一个大顶堆。最大值就是堆顶的根结点,将其移去(其实就是将第一个元素与最后一个元素对调,最后一个元素就是最大值),然后再对剩下的n-1个元素组成的序列从新排序成大顶堆。如此重复,就能得到一个有序序列。


循环方式实现代码

/*堆调整函数,注意我们对于顺序表sqlist默认是第一个元素不用
     * 调整顺序表sqList在s与其左右子树的 序列,m是堆的长度
     * */
    public void heapAdjust(int sqList[],int s,int m){
        int temp = sqList[s];
        for (int i = 2*s ; i <= m; i*=2) {//沿着关键字大的向下筛选
            if (sqList[i]<sqList[i+1] && i<m) {
                i++;//j为记录关键字较大的下标
            }
            if (sqList[i] <= temp) {
                break ;//已经满足堆排序条件,直接跳出
            }
            sqList[s] = sqList[i];
            s = i ;
        }
        sqList[s] = temp;
    }

    /*对顺序表sqlsit进行多排序*/
    public void heapSort(int sqList[]){
        //首先对顺序表改成一个大堆顶
        for (int i = sqList.length/2; i > 0; i--) {
            heapAdjust(sqList, i,sqList.length);
        }
        for (int i = sqList.length; i > 1 ; i--) {
            swap(sqList,1,i);//将最大的一个换到后边
            heapAdjust(sqList, 1,i-1);//对除了已经排好序的记录进行堆调整
        }
    }

递归方式实现代码

/************************
     * 大顶堆排序,堆为A[1...length],不用A[0]
     **************************/

    public int parent(int i) {
        return i / 2;
    }

    public int leftChild(int i) {
        return 2 * i;
    }

    public int rightChild(int i) {
        return 2 * i + 1;
    }

    /*
     * 用递归的思想实现堆调整
     * 
     * @param sqList 是待调整的顺序表
     * 
     * @param i 是需要调整元素的索引
     * 
     * @param length 堆的长度
     */
    public void heapAdjust(int[] sqList, int i, int length) {
        int l = leftChild(i);
        int r = rightChild(i);
        int largest = i;// 最大值的索引
        // 通过两次比较,从根和他的左右孩子之间找出最大值的索引
        if (l <= length && sqList[i] < sqList[l]) {
            largest = l;
        }
        if ( r <= length && sqList[largest] < sqList[r] ) {
            largest = r;
        }
        // 将sqlist[largest]和sqlist[i]交换
        if (largest != i) {
            swap(sqList, i, largest);
            // 由于sqlist[largest]和sqlist[i]交换,
            // 可能造成sqlist不在满足大顶堆性质,所以要调整
            heapAdjust(sqList, largest, length);
        }
        //如果largest==i则已经满足大顶堆条件,就不需要做任何操作。

    }

    // 建堆
    // 由于我们不用sqlist[0],所以堆长度为length-1
    public void buildHeap(int[] sqList) {
        for (int i = (sqList.length-1) / 2; i > 0; i--) {
            heapAdjust(sqList, i, (sqList.length-1));
        }
    }

    // 堆排序
    // 堆的长度为length-1
    public void heapSort(int[] sqList) {
        buildHeap(sqList);
        for (int i = (sqList.length-1); i >= 2; i--) {
            swap(sqList, 1, i);// 将根结点换到后边
            heapAdjust(sqList, 1, i - 1);// 堆调整
        }
    }

    public void swap(int array[], int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }

堆排序时间复杂度

堆调整的时间复杂度为O(logi)
构建堆需要n-1次堆调整,所以构建堆时间复杂度为O(nlogn)
堆排序需要一次堆构,n-1次交换和n-1次堆调整。所以堆排序的时间复杂度为O(nlogn)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值