排序算法(二):堆排序

堆排序:堆是指每个节点值大于/小于其左右节点值的完全二叉树,根节点一定是堆的所有节点中最大/小节点所在处。节点值大于左右节点值的堆叫大顶堆,根元素为整个堆的最大值。节点值小于左右节点值的堆叫小顶堆。

堆排序过程:

1、将无序数组构建成堆结构。

2、将根节点值与最后一个节点值互换,此时最后一个节点值最大

3、将剩下的n-1个节点重新构造为堆结构,继续步骤2,3,直至数组有序

堆排序是基于完全二叉树的数据结构,在堆排序的过程中会用到一些完全二叉树的性质,如下:(以下n均为节点个数)。

2i > n,则i节点没有左子树,2i + 1 > n,则i节点没有有子树。i从1开始算。

在完全二叉树中,最后一个非叶子节点的是第(n-1)/2个节点,此为完全二叉树的性质,自己尚未验证。但是数组的下标是从0开始的,所以最后一个非叶子节点的下标为(n-1-1)/2 = n/2 -1,n为数组长度。

此代码建立的是大堆,得到升序结果,最后一个非叶子节点开始调整

public class HeapSort {
    public static int[] heapSort(int[] arr){
        int length = arr.length;
        for (int i = length -1;i >0;i--){
            //将堆顶元素与最后一个元素互换
            int max = arr[0];
            arr[0] = arr[i];
            arr[i] = max;
            //再次调整剩余堆
            adjustHeap(arr,0,i);
        }
        return arr;
    }

    /**
     * @desc 构建初始堆
     * @param arr
     * @return
     */
    public static int[] init(int[] arr){
        int length = arr.length;
        //下标是从0开始的 最后一个节点的下标为length-1,所以(length-1-1)/2 = length/2 -1
        for (int k = length/2 -1;k >= 0;k--){
            adjustHeap(arr,k,length);
        }
        return arr;
    }

    /**
     * @desc 将当前节点i与其所有子树调整为堆结构
     * @param arr 待调整数组
     * @param i 当前节点
     * @param length 数组长度
     * @return
     */
    public static int [] adjustHeap(int arr[],int i,int length){
        int temp = arr[i];
        //默认当前节点的左节点更大
        for (int larger = 2*i+1;larger < length;larger = 2*i+1){
            int right = larger + 1;//即2*i + 2。i的右节点,可能不存在。
            //取左右节点中较大者
            //存在右节点&&右节点值>左节点值
            if (right < length && arr[right] > arr[larger]){
                larger = right;
            }
            //将左右节点的较大者与父节点比较,若arr[larger]更大,将arr[larger]上移到i位置,也就是当前的父节点位置
            //将父节点位置指向larger,注意此时并没有将父节点的值放到larger,因为经过调整后,larger之后的元素可能不满足堆结构
            //所以还要进一步判断找到父节点的最终位置,只是将父节点的位置暂时指向了larger
            if (arr[larger] > temp){
                arr[i] = arr[larger];
                i = larger;
            }else {
                //父节点比孩子节点都大,即当前位置满足堆结构
                break;
            }
        }
        arr[i] = temp;
        return arr;
    }
}

堆排序是一种选择排序,整体主要由构建初始堆+交换堆顶元素和末尾元素并重建堆两部分组成。其中构建初始堆经推导复杂度为O(n),在交换并重建堆的过程中,需交换n-1次,而重建堆的过程中,根据完全二叉树的性质,[log2(n-1),log2(n-2)...1]逐步递减,近似为nlogn。所以堆排序时间复杂度一般认为就是O(nlogn)级。

参考:https://www.cnblogs.com/chengxiao/p/6129630.html

猜你喜欢

转载自blog.csdn.net/xybz1993/article/details/80217260
今日推荐