排序算法-堆排序

堆排序有最大堆,最小堆。
最大堆:非叶子节点比左右子节点要大
最小堆:非叶子节点比左右子节点要小

以构建最大堆为例,堆排序的过程:
1、原始数组形成一个顺序堆。数组中下标索引为i的节点,左节点是i2 +1,右节点是i2+2
2、初始化堆,从最后一个叶子节点的父节点开始一层层向上遍历,使得每一对父子节点中的最大节点上浮,维持最大堆的性质。
如果有交换位置的操作,那么要以交换后的新子节点为父节点递归遍历,以维持该分支上的最大堆性质。
直到遍历到根节点,此时根节点最大。
3、排序阶段:将根节点与最后一个叶子节点交换位置,交换过位置的尾部叶子节点就是从小到大的排序,最后的叶子节点的索引相对应也减1。
然后以根节点,维护最大堆性质,同样的,如果有交换位置的操作,那么要以被交换的子节点为父节点递归遍历,以维持该分支上的最大堆性质

个人认为,堆排序的核心点在于:如果有交换位置的操作,那么要以交换后的新子节点为父节点递归遍历,以维持该分支上的最大堆性质

以下是java代码:

public static void main(String[] args){
        Integer[] arr = new Integer[]{23,123,234,1,3,432,67,3,56,24,23,7876,124,12,898,854,85,98,2,879};
        heapSort(arr);
        for(Integer i:arr){
            System.out.println(i);
        }
    }

    /**
     * 构建最大堆,数组最终结果由小到大排列
     * 形成堆之后,数组中下标索引为i的节点,左节点是i*2 +1,右节点是i*2+2
     * @param arr
     */
    public static void heapSort(Integer[] arr){
        initHeap(arr);
        //正式排序
        for(int i=arr.length-1;i>=0;i--){
            exchange(arr,0,i);//根节点与尾部节点交换,尾部节点组成由小到大的有序数组
            //交换后,维护以根节点为父节点的最大堆。
            keepMaxHeap(arr,0,i);//最后的叶子节点的上限值也相应发生变化
        }
    }

    /**
     * 初始化堆,形成一个最大堆
     * @param arr
     */
    public static void initHeap(Integer[] arr){
        int i = 0;
        if(arr.length%2==0){
            i=(arr.length-2)/2;
        }else{
            i=(arr.length-3)/2;
        }
        // 从最后一个叶子节点的父节点开始一层层向上遍历
        for(;i>=0;i--){
            keepMaxHeap(arr,i,arr.length);
        }
    }

    /**
     * 维护以index为父节点的最大堆
     * 较大节点上浮
     * @param arr
     * @param index 需要操作的父节点的下标索引
     * @param endIndex 子节点不可超过的最大下标索引,index<endIndex
     */
    public static void keepMaxHeap(Integer[] arr, int index, int endIndex){
        if(arr ==null || index>endIndex){
            return;
        }
        int parentIndex = index;
        int leftIndex = parentIndex*2 +1;
        int maxNodeIndex = parentIndex;
        if(leftIndex<endIndex && arr[maxNodeIndex] < arr[leftIndex]){
            //左节点比父节点大
            maxNodeIndex = leftIndex;
        }
        int rightIndex = leftIndex +1;
        if(rightIndex<endIndex && arr[maxNodeIndex] <arr[rightIndex]){
            //右节点比左,父节点中最大的还大
            maxNodeIndex = rightIndex;
        }
        if(maxNodeIndex!=parentIndex){
            //说明父节点不是最大的,需要交换位置
            exchange(arr,parentIndex,maxNodeIndex);
            //交换位置后要继续向下递归,维持最大堆的性质
            keepMaxHeap(arr,maxNodeIndex,endIndex);
        }
    }

    public static void exchange(Integer[] arr,int i,int m){
        Integer temp = arr[i];
        arr[i]=arr[m];
        arr[m]=temp;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值