二.堆排序

来源:互联网 发布:access sqlserver编程 编辑:程序博客网 时间:2024/06/05 02:47

堆排序

在堆排序中,使用了堆的数据结构,结构如下图:
堆
这个(二叉)堆是一个数组,可以看成一个近似的完全二叉树,树上的每一个节点对应数组的一个元素,除了最底层外,该树是完全的,而且从左到右填充,其高度为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