堆排序

优先队列可以用于以O(NlogN)时间复杂度的排序,基于该思想的算法叫做堆排序(HeapSort)。

二叉堆概念忘记的请看:优先队列的实现与应用

思路与优化

基本思路:
建立N个元素的二叉堆,这个阶段花费O(N)时间,然后执行N次deleteMin操作,最小的元素先出堆(将其记录到第二个数组,因此需要O(N)的空间复杂度),最后得到N个元素的排序。每次deleteMin花费O(logN)时间,因此总时间复杂度为O(NlogN)。
优化思路:
基本思路的主要问题是空间复杂度,它使用了一个额外数组,存储需求增大了一倍。一个优化的方式是,在每次deleteMin后,堆缩小1。因此位于堆中最后的单元可以用来存放刚刚删去的元素。

更细致的思路分析见:堆排序算法 (个人认为写得不错)

Java实现

package algorithmAndDataStructure;

// 该堆排序以小顶堆为例
public class HeapSort {
    public static void heapSort(int[] arr) {
        if (arr == null || arr.length == 1) return;
        // 建堆
        buildHeap(arr);
        int len = arr.length;
        while (len > 1) {
            // 把堆顶和最后一个元素交换
            swap(arr, 0, len - 1);
            // 交换完后,从逻辑上去掉最后一个元素
            len--;
            // 调整顺序,使其满足小(大)顶堆的性质
            heapfy(arr, 0, len);
        }
    }

    // 保持小顶堆
    private static void heapfy(int[] arr, int i, int len) {
        while (true) {
            // 最小值的位置
            int minPosition = i;
            int leftChild = 2 * i + 1;// 左子结点在数组中的索引
            int rightChild = 2 * i + 2;// 右子结点在数组中的索引

            // 若左子结点的值大于最大值,更新最大值
            if (leftChild < len && arr[leftChild] < arr[minPosition]) {
                minPosition = leftChild;
            }

            // 若右子结点的值大于最大值,更新最大值
            if (rightChild < len && arr[rightChild] < arr[minPosition]) {
                minPosition = rightChild;
            }

            if (minPosition == i) {
                break; // 表示已建成小顶堆
            } else {
                swap(arr, i, minPosition);
                i = minPosition;
            }
        }
    }

    // 交换数值的函数
    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    // 建堆方法
    public static void buildHeap(int[] arr) {
        // 此处i的值为最后一个非叶子结点的索引位置
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            heapfy(arr, i, arr.length);
        }
    }

    // 打印数组
    public static void print(int[] arr) {
        if (arr == null) return;
        for (int i : arr) {
            System.out.print(i + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int[] arr = {3, 7, 11, 0, 8, 5, 18, 9, 1, 2};
        System.out.print("排序前:  ");
        print(arr);
        heapSort(arr);
        System.out.print("排序后:  ");
        print(arr);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值