堆排序 【排序算法篇】

升序:最大堆,降序:最小堆
构造最大堆后,我们就知道了在当前无序区间里,最大的值是哪个,即堆顶元素,取出来放至有序区间,就像选择排序。
那么如何构造最大堆or最小堆?
::不断调整,最终形成

  堆排序流程:1、初始化堆 2、获取堆顶元素,并移除它,重新构造堆

图解

以下动图均取自网络

  • 初始化最大堆:先从底层开始比较交换构建堆 自 底 向 上 自底向上
    在这里插入图片描述

  • 调整最大堆:先从顶层开始比较交换构建堆 自 顶 向 下 自顶向下
    在这里插入图片描述


代码模板(升序)

public void get() {
    int[] arr = new int[]{3, 4, 5, 1, 2, -1, 0, 9, 4, 2};
    heapSort(arr);
    for (int i : arr) {
        System.out.println(i);
    }
}
public void heapSort(int[] arr) {
    int num = arr.length;

    //初始化最大堆
    for (int i = (num - 2) / 2; i >= 0; i--) {
        adjustTheHeap(arr, i, num);
    }

    //1、将堆顶元素与无序区间末尾元素交换,如此无序区间末尾元素成为有序区间的一份子,无序区间长度-1
    //2、经过第一步,最大堆已经打乱(堆顶元素不符合要求),重新调整为最大堆,注意:无序区间长度
    for (int i = num - 1; i > 0; i--) {
        swap(arr, 0, i);
        adjustTheHeap(arr, 0, i);
    }
}

/**
 * 最大堆:要求-父节点的值比其子节点大
 * 调整堆:在调整之前我们对被调整的堆是有要求的,该堆必须是除了堆顶元素不符合(父大子小)要求外,其他节点都需符合要求
 * 否则无法调整为最大堆
 *
 * 本函数的主要作用是将错误的堆顶元素移到正确的位置上
 *
 * @param arr   原数组
 * @param index 节点索引,该节点为堆顶元素
 * @param num   无序区间长度
 */
public void adjustTheHeap(int[] arr, int index, int num) {
    int maxChild;
    while ((maxChild = (index << 1) + 1) < num) { //当前节点的左子节点未超出无序区间(表示左子节点存在),进行如下操作
        //若当前节点有左右两个子节点,先让它们先进行比较,选出较大的
        if (maxChild + 1 < num && arr[maxChild] < arr[maxChild + 1]) {
            maxChild++;
        }
        //当前节点与子节点进行比较,若当前节点大于其子节点,那么不用交换
        if (arr[index] > arr[maxChild]) break;
        //否则交换,此时父节点就是三者之间最大的那个值了
        swap(arr, index, maxChild);
        //交换后,原来的父节点,变成了子节点,我们选定该节点,重复以上的操作
        index = maxChild;
    }
}


/**
 * 交换
 */
public void swap(int[] arr, int i, int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}
  • 注 意 : 注意:
  • m a x = ( i n d e x < < 1 ) + 1 正 确 , m a x = i n d e x < < 1 + 1 错 误 , 优 先 级 问 题 max=(index << 1) + 1 正确,max=index << 1 + 1 错误,优先级问题 max=(index<<1)+1max=index<<1+1
  • 时 间 复 杂 度 : O ( n l o g n ) , 空 间 复 杂 度 : O ( 1 ) 时间复杂度:O(nlogn),空间复杂度:O(1) O(nlogn),O(1)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值