堆排序-java

来源:互联网 发布:冰点降低数据法 编辑:程序博客网 时间:2024/05/22 03:16

堆的定义:对于所有的节点,均满足其子节点元素小于(大于)改节点元素的值

根据根节点元素的大小,可以分为:

小顶堆:节点的子元素比该节点元素要大。

大顶堆:节点的子元素比该节点元素要小。


堆排序的原理(以小顶堆为例):

对于满足堆结构的数组,其最小的元素为根元素,即数组的第一个。

在操作的时候,先从一个堆结构中取出最小的一个,与堆中最末尾的元素交换位置,将堆的容量减一,然后重构堆。

剩下的操作就是重复上一步操作,直到堆中只剩下一个元素,这个时候整个数组就是排好序的,降序的数组。

关于重构:
除了根节点,其他的元素均满足堆结构,所以要做的就是将根节点所在位置的元素从上往下移动,使其整个都满足堆结构。
具体:
根元素的子节点先比较大小,比较小的那个再与根节点比较,如果比根节点还小,那么两者交换位置。
现在在根位置的元素已经是剩下的堆中最小的元素了,为了保证剩余的结构也保持堆特性,这个被换下来的根节点还得继续往下走。
重复以上的动作,直到他的子节点没有比他小的,或者是他不再有子节点。

贴代码:

package com.aii.sort;import java.util.Arrays;public class HeapSort {/** * sort an array desc * */public void sort(int[] array) {// init heap// last index : array.length-1// first need to adjust : ((array.length-1)-1)/2=(array.length-2)/2for (int i = (array.length - 1) / 2; i >= 0; i--) {heapAdjust(array, i, array.length - 1);}// finshed adjust --the first heapSystem.out.println("finish init--current array is "+ Arrays.toString(array));// for loop get the min element from the arrayint start = 0;int end = array.length - 1;while (true) {// get the first then swap with the lastint minInArray = array[0];array[0] = array[end];array[end--] = minInArray;System.out.println("start --"+start+"end -- "+ end);if (end == start) {break;}heapAdjust(array, start, end );}System.out.println("sorted array : "+Arrays.toString(array));}private void heapAdjust(int[] array, int start, int end) {System.out.println(Arrays.toString(array) + "--" + start + "--" + end);if (start > end || start < 0 || end >= array.length) {throw new RuntimeException("bounds error");}int leftLeaf = start * 2 + 1;int rightLeaf = start * 2 + 2;/** * if exits children && children leaf smaller than start * */while ((leftLeaf <= end && array[leftLeaf] < array[start])|| (rightLeaf <= end && array[rightLeaf] < array[start])) {// no right leafif (rightLeaf > end) {// left small than startif (array[leftLeaf] < array[start]) {int tmp = array[start];array[start] = array[leftLeaf];array[leftLeaf] = tmp;}// not right so breakbreak;}// has right leaf// get min between left and rightint minIndex = array[leftLeaf] < array[rightLeaf] ? leftLeaf: rightLeaf;// compare child with startif (array[start] >= minIndex) {int tmp = array[start];array[start] = array[minIndex];array[minIndex] = tmp;heapAdjust(array, minIndex, end);}break;}}}


时间复杂度为何为n*logn

对于一个长度为n的数组,从堆中的第一个取元素,然后进行重建,知道堆中只剩下1个元素:这样的操作需要重复n-1次。

数组的长度为n,数的高度即为logn,重构的时候,将堆中的第一个元素(刚从末尾移上去的元素)往下移动的时候,最坏情况下是要移动logn-1次。

所以以上操作耗时( n - 1 ) * ( logn -1 )

初始化的时候,数组长度为n,从(n-2)/2开始到0位置,都要重构,重构这么多次。每次重构最坏的情况也算他是logn-1。初始化需要时间((n-2)/2+1)*(logn-1)


两者相加,时间复杂度还是O(n*logn).


0 0