详细解析堆排序java实现

一、堆是什么

  1. 堆是一种数据结构,一般用一个数组表示,比如int[]
  2. 堆与数组的区别是: 堆的下标表示是由三个组成,分别是 n,2n+1,2n+2 其中
    n称为父节点2n+1称为左子节点2n+2称为右子节点
  3. 由于堆结构,把数据规划成一个图,类似树形结构 ,跟完全二叉树类似,所以,一个堆结构中,也会有根节点非叶子节点,叶子节点根节点指的是下标为0的数据,非叶子节点指的是既不是根节点,又含有子节点的数据。

二、最大顶堆和最小顶堆

每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。如下图:
在这里插入图片描述

三、堆排序的思想

堆排序是基于堆这种数据结构的排序,一般基于最大堆进行排序,默认堆的根节点是最大值,所以获取最大值
的时间复杂度是O(1),而其他值是无序的,但是父节点一定大于子节点。堆排序的思想是,每次把最大值跟数
组里最后一个值交换,然后把剩下的数据当做一个新的堆,然后重新调整新堆为最大堆,然后再把最大值和倒
数第二位交换位置,依次循环执行。由于调整堆的方法是一样的,只需循环调用用调整的方法,传入不同的数
组长度值即可。详细请看以下的代码过程。

四、堆排序的java实现和详解

public static void main(String[] args) {
        int[] arr=new int[]{1,3,2,9,10,7,8,1,63,18,21,1,0,-1,99,100};
        sort(arr,false);  //正序 ,正序构建最大顶堆
//        sort(arr,true);  //反序 , 反序构建最小顶堆
        System.out.println(Arrays.toString(arr));
    }

    /**
     * 堆排序 主要分两步:
     * 第一步:构建最大顶堆。
     * 调整的顺序:自下而上,自左向右调整
     * 方法:从最大的非叶子的节点,开始调整
     * code:最大的非叶子的节点下标是  floor((n-1)/2)
     *
     * 第二步:排序
     *
     * 交换最大值到数组最后
     * 调整剩余的数组成的堆。
     *
     */
    public static void sort(int[] arr,boolean reverse){
        for (int i = arr.length/2-1; i >=0; i--) {       // 构建最大/小顶堆
            adjustHeap(arr,i,arr.length-1,reverse);
        }
        for (int i = arr.length-1; i >=0; i--) {
            swap(arr,0,i);                    //交换根节点和数组最后一个数
            adjustHeap(arr,0,i-1,reverse);  //从根节点开始重新调整
        }
    }

    /**
     *  调整方法:
     * @param arr
     * @param current 当前节点
     * @param length
     */
    public static void adjustHeap(int[] arr,int current,int length,boolean reverse){
        int li = (current << 1) + 1; // 左子节点索引  index * 2 +1
        int ri = li + 1;            // 右子节点索引  左子节点+1
        int temp = li;              //  子节点最大值的索引
        if (li > length) return;  // 子节点索引超出计算范围,直接返回。
        if(reverse){
            if (ri<=length && arr[ri] < arr[li]) {// 先判断左右子节点,哪个较小。
                temp = ri;                          //保存最小值的下标
            }
            if (arr[temp] < arr[current]) {         //比较当前节点和子节点的最小值
                swap(arr,temp,current);             // 交换位置
                adjustHeap(arr,temp,length,true); // 如果原有最小值还有子节点,向下递归,从下往上调整
            }
        }else {
            if (ri<=length && arr[ri] > arr[li]) {// 先判断左右子节点,哪个较大。
                temp = ri;  //保存最大值的下标
            }
            if (arr[temp] > arr[current]) { //比较当前节点和子节点的最大值,哪个大,交换位置
                swap(arr,temp,current);     // 交换位置
                adjustHeap(arr,temp,length,false); // 如果原有最大值还有子节点,向下递归,从下往上调整
            }
        }

    }

    /**
     *  交换位置
     * @param arr
     * @param max
     * @param current
     */
    public static void  swap(int[] arr,int max,int current){
        int temp=arr[max];
        arr[max]=arr[current];
        arr[current]=temp;
    }
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值