堆排序
算法分析:
堆排序的思想是利用数据结构--堆。具体的实现细节:
1. 构建一个最大堆。对于给定的包含有n个元素的数组A[n],构建一个最大堆,从最下层最右边的非终端结点开始构建,将它与其孩子进行比较和若有必要的互换,调整这个堆结构,使其满足最大堆的特性。当为了满足最大堆特性时,堆结构发生变化,此时递归调整对应的子树。
2. 堆排序算法,每次取出该最大堆的根节点,同时,取最末尾的叶子节点来作为根节点,从此根节点开始调整堆,使其满足最大堆的特性。
3. 重复上一步操作,直到堆的大小由n个元素降到2个。
4. gif 演示:http://upload.wikimedia.org/wikipedia/commons/4/4d/Heapsort-example.gif (来自wikipedia)
时间复杂度分析:O(NlogN)
在构建堆的过程中,因为我们是完全二叉树从最下层最右边的非终端结点开始构建,将它与其孩子进行比较和若有必要的互换,对于每个非终端结点来说,其实最多进行两次比较和互换操作,因此整个构建堆的时间复杂度为O(n)。
在正式排序时,第i次取堆顶记录重建堆需要用O(logi)的时间(完全二叉树的某个结点到根结点的距离为.log2i.+1),并且需要取n-1次堆顶记录,因此,重建堆的时间复杂度为O(nlogn)。
所以总体来说,堆排序的时间复杂度为O(nlogn)。由于堆排序对原始记录的排序状态并不敏感,因此它无论是最好、最坏和平均时间复杂度均为O(nlogn)。这在性能上显然要远远好过于冒泡、简单选择、直接插入的O(n2)的时间复杂度了。
空间复杂度上,它只有一个用来交换的暂存单元,也非常的不错。不过由于记录的比较与交换是跳跃式进行,因此堆排序也是一种不稳定的排序方法。
public class HeapSort { public int[] heap; public int heapsize; public HeapSort(int[] array) { this.heap = array; heapsize = array.length; } //建堆,从heapsize/2-1处开始 public void buildMaxHeap() { for(int i = heapsize/2 - 1; i >= 0; i --) { maxify(i); } } //调整,递归 public void maxify(int i) { int left = 2*i+1; int right = 2*i+2; int max = i; if(left < heapsize && heap[left] > heap[i]) { max = left; } if(right < heapsize && heap[right] > heap[max]) { max = right; } if(max == i) { return ; } int tmp = heap[i]; heap[i] = heap[max]; heap[max] = tmp; maxify(max); } //堆排序 public void heapSort() { for(int i = 0; i < heap.length; i ++) { int tmp = heap[0]; heap[0] = heap[heapsize - 1]; heap[heapsize - 1] = tmp; heapsize --; maxify(0); } } public static void main(String[] args) { int[] a = {1,2,3,4,5,6,7}; HeapSort hs = new HeapSort(a); hs.buildMaxHeap(); for (int i : a) { System.out.print(i + " "); } System.out.println(); hs.heapSort(); for(int i : a) { System.out.print(i + " "); } } }