排序算法之堆排序

堆排序详解


一、堆排序相关简介

堆:符合以下两个条件之一的完全二叉树:

  • 根节点的值 ≥ 子节点的值,这样的堆被称之为最大堆,或大顶堆 。
  • 根节点的值 ≤ 子节点的值,这样的堆被称之为最小堆,或小顶堆 。

堆排序过程如下:

  • 用数列构建出一个大顶堆,取出堆顶的数字;
  • 调整剩余的数字,构建出新的大顶堆,再次取出堆顶的数字;
  • 循环往复,完成整个排序。

整体的思路就是这么简单,我们需要解决的问题有两个:

  • 如何用数列构建出一个大顶堆;
  • 取出堆顶的数字后,如何将剩余的数字调整成新的大顶堆。

构建大顶堆有两种方式:

  • 从 0 开始,将每个数字依次插入堆中,一边插入,一边调整堆的结构,使其满足大顶堆的要求;
  • 将整个数列的初始状态视作一棵完全二叉树,自底向上调整树的结构,使其满足大顶堆的要求。

在介绍堆排序具体实现之前,我们先要了解完全二叉树的几个性质。将根节点的下标视为 0,则完全二叉树有如下性质:

  • 对于完全二叉树中的第 i 个数,它的左子节点下标:left = 2i + 1
  • 对于完全二叉树中的第 i 个数,它的右子节点下标:right = left + 1
  • 对于有 n 个元素的完全二叉树(n≥2)(n≥2),它的最后一个非叶子结点的下标:n/2 - 1

二、堆排序的代码实现

public class Heapsort {

    public static void main(String[] args){

        int[] arr = {2,3,5,1,2,4,5,6,8,6,7,9};
        heapSort1(arr);
        for (int i : arr) {
            System.out.print(i+"-");
        }
    }

    public static void heapSort1(int[] arr){
        buildMaxHeap(arr);
        for (int i = arr.length-1; i > 0 ;i --){

            swap(arr,0,i);

            maxHeapify(arr,0,i);
        }
    }

    /**
     * 初始化大顶堆
     */
    public static void buildMaxHeap(int[] arr){

        //从最后一个非叶子节点开始,向上调整
        for (int i = arr.length/2 -1 ; i >= 0 ; i--){
            maxHeapify(arr,i,arr.length);
        }
    }

    public static void maxHeapify(int[] arr, int i, int heapSize){

        //左子节点的下标
        int left = 2 * i + 1;

        //右子节点的下标
        int right = 2 * i + 2;

        //记录根节点,左子节点,右子节点三者中最大值小标
        int largest = i;

        if (left < heapSize && arr[left] > arr[largest]){

            largest = left;
        }
        if (right < heapSize && arr[right] > arr[largest]){

            largest = right;
        }
        if (i != largest){

            swap(arr,i,largest);

            maxHeapify(arr,largest,heapSize);
        }
    }

    public static void swap(int[] arr, int i ,int j){

        int temp = arr[i];

        arr[i] = arr[j];

        arr[j] = temp;
    }
}


三、堆排序时间复杂度 & 空间复杂度

堆排序分为两个阶段:初始化建堆(buildMaxHeap)和重建堆(maxHeapify,直译为大顶堆化)。所以时间复杂度要从这两个方面分析。

根据数学运算可以推导出初始化建堆的时间复杂度为 O(n),重建堆的时间复杂度为 O(n\log n),所以堆排序总的时间复杂度为 O(n\log n)。推导过程较为复杂,故不再给出证明过程。

堆排序的空间复杂度为 O(1),只需要常数级的临时变量。


参考文章地址:https://leetcode-cn.com/leetbook/read/sort-algorithms/eu7ux3/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值