堆排序

堆,是一种类似于二叉树的数据结构。
它分为大顶堆和小顶堆,以大顶堆为例,大顶堆的每一个父节点一定大于它的左右子节点;小顶堆顾名思义。

大致步骤

所以,利用这种性质,便可以实现数组的排序。步骤如下:

  1. 以大顶堆为例(通常用于升序排列),先将数组的元素构成一个大顶堆;
  2. 取出堆顶元素,一定是最大的,然后放在数组末尾(交换数组末尾元素);
  3. 剩下的元素重新组成一个大顶堆,然后再次取出堆顶元素,放在上一个的前面;
  4. 以此类推,直到堆中无元素,数组也就排好序了。

构建大顶堆

以上就是堆排序的大致过程,那么如何构建一个大顶堆呢?具体实现如下:

  1. 从后向前扫描所有的非叶子节点(叶子节点一定符合要求),判断是否符合大顶堆要求,不符合则与子节点交换。
  2. 注意,如果交换完成后,子节点不符合大顶堆要求了,那么就重新将该子节点转换为大顶堆。
  3. 还有,假如数组长length,最后一个非叶子节点的下标为(length-2)/2
  4. 假如节点下标为i,则左子节点下标为2*i+1,右子节点下标为2*i+2

代码

public class HeapSort {
    /**
     * 用于每一次构造一个大顶堆
     * @param arr 数组
     * @param length 当前大顶堆所对应长度
     */
    public void heapSort(int[] arr,int length){
        for(int i=(length-2)/2;i>=0;i--){
            heapfy(arr,i,length);
        }
    }

    /**
     * 用于将每一个节点大顶堆化
     * @param arr 数组
     * @param root 当前节点
     * @param length 当前大顶堆对应长度
     */
    private void heapfy(int[] arr, int root, int length) {
        int left = root*2 + 1;  //左子节点的下标
        int right = root*2 + 2; //右子节点的下标
        int max_index = left;    //表示左右子节点较大的那个下标,默认为left,一会儿交换的就是这个
        if(right<length){   //当存在右子节点时,取最大的
            max_index = arr[left]>arr[right]?left:right;
        }
        if(arr[root]<arr[max_index]){   //假如不符合大顶堆要求
            int temp = arr[root];
            arr[root] = arr[max_index];
            arr[max_index] = temp;  //交换两个值
            if(max_index<=(length-2)/2){    //当子节点不是叶子节点时,才需要对子节点堆化
                heapfy(arr,max_index,length);   //为防止交换后子节点不符合大顶堆了,就重新对它大顶堆化
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = {2,3,5,1,6,4};
        HeapSort heapSort = new HeapSort();
        for(int i=arr.length-1;i>0;i--){    //i从数组后向前遍历,负责控制每次堆排序的长度
            heapSort.heapSort(arr,i+1);
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;  //交换头尾元素
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值