二.堆排序

堆排序

在堆排序中,使用了堆的数据结构,结构如下图:
堆
这个(二叉)堆是一个数组,可以看成一个近似的完全二叉树,树上的每一个节点对应数组的一个元素,除了最底层外,该树是完全的,而且从左到右填充,其高度为log2n。在一个堆中,它的父节点i对应的子节点分别为2i跟2i+1,二叉堆可以分成最大堆跟最小堆,在最大堆中,某个节点的值最多与其父节点一样大,而最小堆刚好与最大堆相反,这里使用最大堆进行排序。
首先,我们通过一个maxHeap方法来维护节点i处最大堆的性质。
Java代码:

public static void maxHeap(int[] arr, int i){
        int l = 2 * i + 1;
        int r = 2 * i + 2;
        int largest = 0;
        if (l <= arr.length - 1 && arr[l] > arr[i]){
            largest = l;
        }else{
            largest = i;
        }
        if (r <= arr.length - 1 && arr[r] > arr[largest]){
            largest = r;
        }
        if (largest != i){
            int temp = arr[i];
            arr[i] = arr[largest];
            arr[largest] = temp;
            maxHeap(arr, largest);
        }
    }

对于树高为h的节点,maxHeap的时间复杂度是O(h),也就是O(log2n)。
maxHeap方法是维护节点i处最大堆的性质,如果对堆的所有非叶节点从底往上得进行维护最大堆的性质,
那么我们就可以得到一个最大堆,
Java代码:

public static void buildMaxHeap(int[] arr){
         for (int i = arr.length / 2; i >= 0; i--){
             maxHeap(arr, i);
         }
     }

这里需要O(n)次调用maxHeap方法,因此buildMaxHeap的时间复杂度为O(nlog2n),但是不同的节点运行maxHeap的时间与该节点为根节点的树高有关,而且大部分节点的高度都很小,buildMaxHeap有一个更紧确的界:O(n)。
堆排序是利用最大堆的堆顶是整个堆中最大的节点的性质进行排序,每次让根节点跟最后一个叶子节点互换,然后把该堆的大小减一重新构建一个最大堆,重复该过程完成堆排序。
由于需要改堆的大小,所以改变maxHeap,最终的Java代码如下:

    public static void heapSort(int[] arr){
        int length = arr.length;
        buildMaxHeap(arr);
        for (int i = arr.length - 1; i >= 1; i--){
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;
            maxHeap(arr, 0, --length);
        }
    }

     public static void buildMaxHeap(int[] arr){
         for (int i = arr.length / 2; i >= 0; i--){
             maxHeap(arr, i, arr.length);
         }
     }

     public static void maxHeap(int[] arr, int i,int length){
         while (i < length){
             int l = 2 * i + 1;
             int r = 2 * i + 2;
             int largest = i;
             if (l <= length - 1 && arr[l] > arr[i]){
                 largest = l;
             }
             if (r <= length - 1 && arr[r] > arr[largest]){
                 largest = r;
             }
             if (largest != i){
                 int temp = arr[i];
                 arr[i] = arr[largest];
                 arr[largest] = temp;
                 i = largest;
             }else{
                 return;
             }
         }
     }

算法分析:
1. 时间复杂度
可以看出最终排序时调用了一次buildMaxHeap,它的时间复杂度为O(n),然后又调用了n-1次maxHeap,而maxHeap的时间复杂度为O(log2n),所以最终堆排序的时间复杂度为O(nlog2n)。
2. 空间复杂度
堆排序具有空间原址性(任何时候都只需要常数个额外的元素空间存储临时的数据)。
测试:
测试1
接下来分别使用10000,100000,500000个随机数进行测试:
测试2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值