首页 > 编程语言 > 详细

堆排序

时间:2021-05-05 11:48:37      阅读:31      评论:0      收藏:0      [点我收藏+]

堆排序应该是几大排序里最复杂的一个了,具体来看:

首先涉及了一个构建大顶堆的方法(升序排序使用大顶堆):

/**
     * 功能:将i对应的非叶子节点为根的树调整成大顶堆
     * 举例 int[] arr = {4, 6, 8, 5, 9}; => i = 1 => adjustHeap => {4, 9, 8, 5, 6}
     * 如果我们再次调用adjustHeap,传入的是i = 0 => {9, 6, 8, 5, 4}
     * @param arr 待调整的数组
     * @param i 表示非叶子结点在数组中的索引
     * @param length 表示对多少个元素继续调整,len在逐渐减少
     */
    public static void adjustHeap(int[] arr, int i, int length) {
        int temp = arr[i]; //先取出当前元素的值,保存在临时变量
        //开始调整
        //说明
        //1. k = i * 2 + 1, k是i结点的左子结点
        for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
            if (k + 1 < length && arr[k] < arr[k + 1]) { //说明左子节点小于右子节点
                k++; //k指向右子结点,至此k指向了左右结点里较大的
            }
            if (arr[k] > temp) { //如果子节点大于父节点
                arr[i] = arr[k]; //把较大的值赋给当前结点
                i = k; //让i指向k,继续循环比较
            } else {
                break;
            }
        }
        //当for循环结束后,已经将以i为父节点的最大值放在了最顶
        arr[i] = temp; //将temp放到调整后的位置

    }

理解这个方法的关键在于,堆排序寻找非叶子结点,是从下到上,从左到右寻找非叶子结点的,第一次传入的索引i,在二叉树中的位置必然是相对靠下的,此时for循环是没作用的。但随着传入的i变化(非叶子结点的逐渐变高),需要对于当前节点高度以下的子树,都已经实现了大顶堆,只是加入当前结点后,这个子树需要重新调整,重新形成新的大顶堆,这时候for循环就开始起作用了,可能会经过多次比较,最终找到当前节点应该放置的位置。这个方法每次执行完,索引i对应的二叉树以下的部分(子树)都实现了大顶堆。

对于方法:

public static void heapSort(int arr[]) {
        int temp;
        System.out.println("堆排序");

        //将无序序列构建成一个堆,根据升序降序需求选择大顶堆和小顶堆
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            adjustHeap(arr, i, arr.length);
        }

        //将堆顶元素与末尾元素交换,将最大元素沉到数组末端
        //重新调整结构,使其满足堆定义,然后继续交换堆顶元素与末尾元素,反复执行,直到整个序列有序
        for (int i = arr.length - 1; i > 0; i--) {
            //交换
            temp = arr[i];
            arr[i] = arr[0];
            arr[0] = temp;
            adjustHeap(arr, 0, i);
        }
        System.out.println(Arrays.toString(arr));
    }

第一个for循环是根据传入i的不同,经过几次循环后实现了全部二叉树的大顶堆。第二个for循环根据在第一次执行时,可以确定的是二叉树的根结点放置的是所有元素中最大的,其他二叉树元素大小关系都不能确定,于是先将这个最大的数放置到数组的最后,也就是对应的二叉树的最低的位置,将最低的元素放到根结点的位置。此时除了根结点,显然其他子树都已经实现了大顶堆,于是剩下的工作就是在不断减小数组长度的同时,将整个数组对应的二叉树重构成大顶堆的形式了。

堆排序

原文:https://www.cnblogs.com/LostSecretGarden/p/14730754.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!