排序算法入门(八)——堆排序

198 阅读2分钟

算法简介

堆排序(Heapsort)是基于堆这种结构而设计的一种程序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为 O(nlogn)O(nlogn)。且是一种不稳定排序。
堆是具有以下性质的完全二叉树:
每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆。
注意 : 没有要求结点的左孩子的值和右孩子的值的大小关系。

算法描述

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

动图演示

849589-20171015231308699-356134237.gif

代码实现

public class Head {
    // 堆排序
    public static int[] headSort(int[] arr) {
        int n = arr.length;
        //构建大顶堆
        for (int i = (n - 2) / 2; i >= 0; i--) {
            downAdjust(arr, i, n - 1);
        }
        //进行堆排序
        for (int i = n - 1; i >= 1; i--) {
            // 把堆顶元素与最后一个元素交换
            int temp = arr[i];
            arr[i] = arr[0];
            arr[0] = temp;
            // 把打乱的堆进行调整,恢复堆的特性
            downAdjust(arr, 0, i - 1);
        }
        return arr;
    }

        //下沉操作
    public static void downAdjust(int[] arr, int parent, int n) {
        //临时保存要下沉的元素
        int temp = arr[parent];
        //定位左孩子节点的位置
        int child = 2 * parent + 1;
        //开始下沉
        while (child <= n) {
            // 如果右孩子节点比左孩子大,则定位到右孩子
            if(child + 1 <= n && arr[child] < arr[child + 1])
                child++;
            // 如果孩子节点小于或等于父节点,则下沉结束
            if (arr[child] <= temp ) break;
            // 父节点进行下沉
            arr[parent] = arr[child];
            parent = child;
            child = 2 * parent + 1;
        }
        arr[parent] = temp;
    }
}