堆排序(Java)

第10章 堆排序

10.1 堆排序基本介绍

1)堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是一种不稳定的排序。

2)堆具有以下性质的完全二叉树:

  • 每个节点的都大于或等于其左右孩子节点的值,称为大顶堆
  • 没有要求节点的左孩子的值和右孩子的值的大小关系
  • 每个节点的值都小于或等于其左右孩纸节点的值,称为小顶堆

大顶堆举例说明:

在这里插入图片描述

小顶堆举例:

在这里插入图片描述

10.2 堆排序的基本思路

1)将待排序序列构造成一个大顶堆

2)此时,整个序列的最大值就是堆顶的根节点

3)将其与末尾元素进行交换,此时末尾就是最大值

4)然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列

(最后一个非叶子节点==最后一个叶子节点的父节点)

(arr.length-1) / 2

思路:
在这里插入图片描述-
在这里插入图片描述

  • 在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 在这里插入图片描述

图解:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

代码实现

package com.ldm.tree;

import java.util.Arrays;

/**
 * @author 梁东明
 * 2022/9/2
 * 人生建议:看不懂的方法或者类记得CTRL + 点击 看看源码或者注解
 * 点击setting在Editor 的File and Code Templates 修改
 * 堆排序
 */
public class HeapSort {
    public static void main(String[] args) {
        int[] arr = {4, 6, 8, 5, 9,-2,99};
        heapSort(arr);
    }
    public static void heapSort(int[] arr){
        System.out.println("堆排序");

        int temp =0;   //临时变量
        //1、将无序数组构建出一个堆,根据升降排序的需求选择大顶堆或者小顶堆
        //这样做的目的是将数组最大或最小的值升到堆顶
        //(arr.length-1)/2  从最后一个非叶子节点开始调整堆
        //至于(arr.length-1)/2怎么得来的,我再提一下:
        //最后一个非叶子节点==最后一个叶子节点的父节点
        //最后一个叶子节点的索引就是arr.length
        for (int i = (arr.length-1)/2; i >= 0;i--){
            adjustHeap(arr,i, arr.length);
        }
        //2、上一步已经把数组最大值升到堆顶了
        //所以我们需要将堆顶元素和末尾元素交换,将最大(小)值放到数组末尾
        //重新调整堆,使arr.length-1的元素继续排成大(小)堆顶,最大值不参与下一次的堆所以要arr.length-1
        //然后循环1、2步的操作,直到完全排序好
        //这个for循环是倒序循环的,看清楚了,每次取出的j就是数组末尾的索引
        for (int j = arr.length - 1; j > 0; j--){
            //交换节点,如果这个还不会,赶紧去学冒泡排序
            temp = arr[j];
            arr[j] = arr[0];
            arr[0] = temp;
            //开始调整堆,记住啦j是递减的,所以需要调整的堆会越来越小
            //直到数组被排序完毕
            adjustHeap(arr,0, j);
        }
        System.out.println(Arrays.toString(arr));
    }

    /**
     * 调整堆
     * 功能:完成将以i对应的非叶子节点的树调整成大顶堆
     *(小提示:要学会这个排序,最好先学会完全二叉树,巧了,我主页刚好有教程,
     * 翻一翻,动个小手去学吧!否则代码你只会有用而看不懂。)
     * @param arr    待调整的数组
     * @param i      表示非叶子节点在数组的索引
     * @param length 表示对多少个元素继续调整,length是在逐渐的减少
     */
    public static void adjustHeap(int[] arr, int i, int length){
        int temp = arr[i]; //先取出当前元素的值,保存在临时变量中
        //开始调整堆
        for (int k = 2*i+1; k <length ; k=2*k+1) {  //如果你了解完全二叉树,你就知道i节点的左子节点就是2*i+1,右子节点就是2*i+2,它们的索引相差1
            if (k+1 <length && arr[k] < arr[k+1]){ //防止数组越界  &&  取出当前i节点的左右子节点比较(如果左子节点小于右子节点,指针就指向右子节点)
                k++;  //k++,这样k就指向了右子节点  。把左右子节点最大值取出来,在下一条语句和i比较
            }
            if (arr[k] > temp){  //如果子节点大于父节点
                arr[i] = arr[k];  //就把较大的值赋值给当前i节点
                i = k;   //i指向k,继续循环比较  ,而且还是自下而上(最重要,理解这行代码基本就懂了)对堆调整
            }else {
                break;
            }
        }
        //当for循环结束时,以i为父节点的树的最大值,放在顶部(局部)
        arr[i] = temp; //将temp值放在调整之后的位置
    }
}


上面的代码是不是看上去很多注解很麻烦?不用担心,接下来的是全无注解(我自己练手写下的代码

直接拿来就可以用了,什么时候你想起来要学了,再把上面的代码研究研究,实在看不懂,我还推荐你去学韩老师的教程,文章末尾有地址,直接点击跳转就可以上b站学习。
这么有良心的博主,你还不关注???赶紧一键三连。

package com.ldm.tree;

import java.util.Arrays;

/**
 * @author 梁东明
 * 2022/9/3
 * 人生建议:看不懂的方法或者类记得CTRL + 点击 看看源码或者注解
 * 点击setting在Editor 的File and Code Templates 修改
 */
public class MyHeapSort {
    public static void main(String[] args) {
        int[] arr = {3,9,12,6,2,4,15};
        heapSort(arr);
    }

    /**
     * 堆排序
     *
     * @param arr 待排序的数组
     */
    public static void heapSort(int[] arr){
        System.out.println("这就是堆排序~");
        int temp = 0;
        for (int k = (arr.length-1)/2;k>=0;k--){
            adjustSort(arr,k, arr.length);
        }
        for (int i = arr.length - 1; i > 0 ; i--) {
            temp = arr[i];
            arr[i] = arr[0];
            arr[0] = temp;
            adjustSort(arr,0,i);
        }

        System.out.println(Arrays.toString(arr));
    }

    /**
     * 调整堆
     *
     * @param arr    传入的数组
     * @param i      开始调整堆的索引
     * @param length 被调整的堆的长度
     */
    public static void adjustSort(int[] arr,int i, int length){
        int temp = arr[i];
        for (int j = 2*i+1; j < length ; j= j*2+1) {
            if (j+1 < length && arr[j] < arr[j+1]){
                j++;
            }
            if (arr[j] > temp){
                arr[i] = arr[j];
                i = j;
            }else {
                break;
            }
        }
        arr[i] = temp;
    }
}


本次堆排序教程出自韩顺平的数据结构与算法

数据结构和算法教程,哔哩哔哩详细教程
在 107-111p.

最后,认识一下,我是小白。努力成为一名合格的程序员。期待与你的下次相遇。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

梁小樽

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

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

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

打赏作者

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

抵扣说明:

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

余额充值