堆排序

首先我们引入一张思维导图,并且以后的排序博客我将以这位博主的博文为基础,进行代码自我实现,简单介绍以及自我理解。
链接:cnblogs.com/cndarren/p/11787368.html
在这里插入图片描述

堆排序的思想:
构建一个大根堆(基于完全二叉树)。当前根就是当前序列的最大值(根节点),与尾结点(未排序的末尾)交换,那么最后一个节点就是最大值了(已排序序列),但是我们破坏了大根堆,然后我们对未排序序列在进行大根堆调整,再把最大值也就是根,与未排序序列的尾结点进行交换。直到未排序序列为0。

有关于图解,请参考链接中的动图,我认为链接中的动图比我画的静态图好太多。
在这里我拿来参考一下。

在这里插入图片描述
实现:

 //构建大根堆
    public static int[] adjust(int[] arr, int start,int end){
            int root = arr[start];   //保存当前根节点,也就是起始节点

            for(int i = 2*start+1 ; i <= end ; i = i*2 +1){   //i 为当前最大值的下标
                //先对比当前二叉树的左右孩子
                //首先确保有右孩子
                if(i+1 <= end && arr[i+1] > arr[i]){ //有右孩子的同时右孩子比左孩子大
                    i++; // 那么我们就让右孩子下标变为最大值的下标
                }

                //再从对比孩子的最大值与根点的大小,如果比父节点大,那么就把左右孩子的最大值放置在父节点上,
                // 让需要调整的二叉树的根的下标设置为左右孩子最大值的节点下标,再进行调整。
                if(arr[i] > root){
                    arr[start] = arr[i];
                    start = i;
                }else { //如果左右孩子都不大于根,那么就证明当前的左右孩子的父节点就是根所存放的位置了 跳出循环
                    break;
                }

            }

            //当我们退出循环的时候,也就证明找到了root节点所需要存放的位置,并且当前根为最大值
            arr[start] = root;

        return arr;
    }
    public static int[] heapSort(int[] arr){
        //首先让待排序列变为完全二叉树
        //从尾节点(最后一个元素)的父节点开始构建二叉树
        //子节点——》父节点 (子节点下标 - 1)/ 2   = 父节点下标
        //父节点——》子节点  父节点下标 * 2 +1 = 左孩子下标  右孩子下标 = 左孩子下标 +1
        for(int i = (( (arr.length-1) -1) /2) ; i >= 0; i-- ){    // arr.length -1 =  尾结点  (尾结点-1 ) /2  = 父节点

            adjust(arr,i,arr.length-1);   //让当前节点到尾结点直接进行 大根堆 二叉树调整

        }
        //全部调整完,当前的root节点(根节点就是当前序列的最大值)

        for(int i = 0 ; i < arr.length ;i++){   //因为当前是大根堆,所以让最大的值与尾结点置换,那么最后一个节点就是当前序列的最大的值,就是有序的了
            int max = arr[0];
            arr[0] = arr[arr.length-1-i];
            arr[arr.length-1-i] = max;
            adjust(arr,0,arr.length-1 -1 -i);  //交换之后,我们破坏了大根堆,
                                        // 我们需要让除了当前尾结点之外的元素进行重新构建大根堆
                                        //构建之后成为大根堆,再进入循环,让最大值与当前的序列的尾结点的倒数前n个交换
                                        //  (第一次进入循环 n = 0,第二次进入循环 n = 1 ,第一次进入循环之后,倒数第一个数字是最大值,那么就是有序的)
                                        //第二次进入序列,倒数第一个数字已经是当前序列的最大值了,所以与倒数第二个数字进行交换,那么最后两个数字就是有序的
                                        //依次类推
        }

        return arr;
    }

时间复杂度:第一建堆的时间复杂度 O(n * log2 n)
空间复杂度:O(1)
稳定性:不稳定 父与子属于跳跃式交换,不稳定

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值