堆是一种数据结构,是一棵像这样的完全二叉树,其任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。堆分为大顶堆和小顶堆,满足Key[i]>=Key[2i+1]&&key>=key[2i+2]称为大顶堆,满足 Key[i]<=key[2i+1]&&Key[i]<=key[2i+2]称为小顶堆。Java中的优先队列PriorityQueue就是基于堆这种数据结构来实现的。
堆排序主要分为两步,建立初始堆,以及移除堆顶元素后的调整,我们以大顶堆为例描述,假设存在整型数组int[] R,数组中有n个元素,那么其堆排序思想如下:
1、将初始待排序关键字序列(R0,R2....Rn-1)构建成大顶堆,此堆为初始的无序区;
2、将堆顶元素R[0]与最后一个元素R[n-1]交换,此时得到新的无序区(R0,R2,......Rn-2)和新的有序区(Rn-1),且满足R[0,2...n-2]<=R[n-1];
3、由于交换后新的堆顶R[0]可能违反堆的性质,因此需要对当前无序区(R0,R2,......Rn-2)调整为新堆,然后再次将R[0]与无序区最后一个元素交换,
得到新的无序区(R0,R2....Rn-3)和新的有序区(Rn-2,Rn-1)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
private static void heapSort(int[] a) { //建立初始堆 for(int i=a.length/2;i>=0;i--) { maxHeap(a,a.length,i); //对整个数组从[a.length/2]处开始调整,到0下标为止 } //去掉根节点后,重新调整 for(int i=a.length-1;i>=1;i--) { swap(a,i,0); maxHeap(a,i,0); } } private static void swap(int[] a,int i,int j) { int tmp = a[i]; a[i] = a[j]; a[j] = tmp; } private static void maxHeap(int[] a,int heapSize,int index){ //沉降法调整 int left = 2 * index + 1; int right = 2 * index + 2; int largeMax = index; if(left < heapSize && a[left] > a[largeMax]) { largeMax = left; } if(right < heapSize && a[right] > a[largeMax]) { largeMax = right; } if(largeMax != index) { swap(a,index,largeMax); maxHeap(a,heapSize,largeMax); } }
涉及到循环和二叉树高度的计算,时间复杂度为O(n*log2^n),只用到一个额外的辅助空间,空间复杂度为O(1)。
堆排序典型的适用场景是从XXXX多个记录里,找出前X个最小的。
原文:http://www.cnblogs.com/mist-lee/p/4784058.html