排序8-堆排序

        利用堆这种数据结构来进行排序的算法, 堆是一种优先队列,它有两种实现,最大堆和最小堆. 

       堆(以下全都默认为最大堆)看成一棵完全二叉树,但是位于堆顶的元素总是整棵树的最大值,每个子节点的值都比父节点小,由于堆要时刻保持这样的规则特性,所以一旦堆里面的数据发生变化,我们必须对堆重新进行一次构建。

  既然堆顶元素永远都是整棵树中的最大值,那么我们将数据构建成堆后,第一次取的元素,就是最大值?取完后把堆重新构建一下,然后再取堆顶的元素,取的就是第二大的值, 反复的取,取出来的数据也就是有序的数据。

1. 示意图: 

以[8,2,5,9,7,3]这组数据来演示. 

首先,将数组构建成堆。
 

接下来,我们取出堆顶的数据,也就是数组第一个数,9,取法是将数组的第一位和最后一位调换,然后将数组的待排序范围-1,

现在的待排序数据是[3,8,5,2,7],我们继续将待排序数据构建成堆。
 

取出堆顶数据,这次就是第一位和倒数第二位交换了,因为待排序的边界已经减1。

继续构建堆

从堆顶取出来的数据最终形成一个有序列表. 

2. 流程描述:

  • 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
  • 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
  • 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

3. java代码实现. 

    /**
     * 堆排序
     * @param arr 排序数组
     */
    public static void sort(int[] arr) {

        int length = arr.length;

        //构建堆
        buildHeap(arr, length);

        for (int i = length - 1; i > 0; i--) {
            //将堆顶元素与末位元素调换
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;

            //数组长度-1 隐藏堆尾元素
            length--;

            //将堆顶元素下沉 目的是将最大的元素浮到堆顶来
            sink(arr, 0, length);
        }
    }

    /**
     * 构建堆
     * @param arr 数组
     * @param length 数组范围
     */
    private static void buildHeap(int[] arr, int length) {
        for (int i = length / 2; i >= 0; i--) {
            sink(arr, i, length);
        }
    }

    /**
     * 下沉调整
     * @param arr 数组
     * @param index 调整位置
     * @param length 数组范围
     */
    private static void sink(int[] arr, int index, int length) {
        int leftChild = 2 * index + 1;//左子节点下标
        int rightChild = 2 * index + 2;//右子节点下标
        int present = index;//要调整的节点下标

        //下沉左边
        if (leftChild < length && arr[leftChild] > arr[present]) {
            present = leftChild;
        }

        //下沉右边
        if (rightChild < length && arr[rightChild] > arr[present]) {
            present = rightChild;
        }

        //如果下标不相等 证明调换过了
        if (present != index) {
            //交换值
            int temp = arr[index];
            arr[index] = arr[present];
            arr[present] = temp;

            //继续下沉
            sink(arr, present, length);
        }
    }

3. 分析:   堆排序的时间复杂度是O(nlogn)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangyingchengqi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值