经典算法(9)- 堆排序(Heapsort)
2011-06-03 00:27
288 查看
堆排序需先建立堆,然后对堆进行操作,每次取根节点值,将它与数组右边位置(即叶子节点)的值交换,交换后完全二叉树的叶子节点数减1,由于此时可能破坏堆的性质,需要向下将新的根节点与它的后代节点交换,直到叶子节点。
首先建立堆的过程可以采用Floyd算法(heapify):
完全二叉树(complete binary tree)和二叉堆都可以用一维数组表示用层序(level order)遍历的结果。Floyd算法将数组表示的任意一颗完全二叉树转换为堆,它无需开辟额外的空间,直接在数组中交换数据(即in-place做法),转换成堆结构,它的时间复杂度只有O(n),而不是预想的O(nlogn)。具体做法是自底向上循环所有的非叶子节点,构建满足堆结构的子堆。最后一个非叶子节点可以这样找到:最后一个叶子节点的父节点就是最后一个非叶子节点,最后一个叶子节点的索引值是n-1,它的父节点索引值是[(n-1)-1]/2 = n/2 -1 (这里使用整数除法,无小数部分)。
上面两个阶段中的维护堆性质的操作可以共用,对应以下的实现中的方法moveDown()。
堆排序第一个阶段的复杂度为O(n),第二个阶段的的复杂度为O(nlogn),所以总的时间复杂度为O(nlogn),和快速排序以及归并排序属于同一类复杂度的排序算法。但是实现时堆排序不需要递归。堆排序的缺点是不稳定(unstable)(这一点类似于选择排序),因为堆的性质决定了位于相邻两个位置的节点的大小关系是不予考虑的,交换操作只是跟祖先节点相关。
实现:
测试输出:
0 1 2 3 4 5 6 7 8 9 10 12 17
首先建立堆的过程可以采用Floyd算法(heapify):
完全二叉树(complete binary tree)和二叉堆都可以用一维数组表示用层序(level order)遍历的结果。Floyd算法将数组表示的任意一颗完全二叉树转换为堆,它无需开辟额外的空间,直接在数组中交换数据(即in-place做法),转换成堆结构,它的时间复杂度只有O(n),而不是预想的O(nlogn)。具体做法是自底向上循环所有的非叶子节点,构建满足堆结构的子堆。最后一个非叶子节点可以这样找到:最后一个叶子节点的父节点就是最后一个非叶子节点,最后一个叶子节点的索引值是n-1,它的父节点索引值是[(n-1)-1]/2 = n/2 -1 (这里使用整数除法,无小数部分)。
上面两个阶段中的维护堆性质的操作可以共用,对应以下的实现中的方法moveDown()。
堆排序第一个阶段的复杂度为O(n),第二个阶段的的复杂度为O(nlogn),所以总的时间复杂度为O(nlogn),和快速排序以及归并排序属于同一类复杂度的排序算法。但是实现时堆排序不需要递归。堆排序的缺点是不稳定(unstable)(这一点类似于选择排序),因为堆的性质决定了位于相邻两个位置的节点的大小关系是不予考虑的,交换操作只是跟祖先节点相关。
实现:
/** * * Heap sort * @author ljs * 2011-06-03 * * */ public class HeapSort { public static void solve(int[] data){ heapify(data); int len = data.length; //sort: remove the top element and put it at the right side int size = len; while(size>0){ //swap int tmp = data[size-1]; data[size-1] = data[0]; data[0] = tmp; size--; //only consider 0...size-1 moveDown(data,0,size); } } /** * 用Floyd算法转换任何一颗完全二叉树为最大值堆(maxheap) * * Build a heap from any non-heap array * 转换数组为堆结构,无需开辟额外的空间(直接在数组中交换in-place) * Floyd Algorithm: O(n) * */ //input: a randomly generated integer array //output: convert it into a maxheap private static void heapify(int[] data){ if(data.length<2) return; //the last nonleaf node's index int nonLeafIndex = data.length/2 - 1; for(int i=nonLeafIndex;i>=0;i--){ moveDown(data,i,data.length); } } //index: the nonleaf node's index //size: the size of array (from 0 to size-1) that is to be heapified private static void moveDown(int[] data,int index,int size){ int target = data[index]; //save the target value to be moved down while(true){ int leftChildIndex = 2*index + 1; int rightChildIndex = leftChildIndex+1; if(rightChildIndex>size-1){ //if right child is empty, left child must be empty or leaf if(leftChildIndex<size){ //left child is leaf if(target<data[leftChildIndex]){ data[index] = data[leftChildIndex]; index = leftChildIndex; } } break; } if(data[leftChildIndex]>data[rightChildIndex]){ //left child is larger if(target<data[leftChildIndex]){ //exchange the max with index node data[index] = data[leftChildIndex]; index = leftChildIndex; }else{ break; } }else{ //right child is larger if(target<data[rightChildIndex]){ data[index] = data[rightChildIndex]; index = rightChildIndex; }else{ break; } } } data[index] = target; } public static void main(String[] args) { int[] data = {2,6,12,17,9,1,0,3,4,8,7,10,5}; HeapSort.solve(data); for(int i=0;i<data.length;i++){ System.out.format(" %d",data[i]); } } }
测试输出:
0 1 2 3 4 5 6 7 8 9 10 12 17
相关文章推荐
- 排序算法 之 堆排序(heapsort)
- 堆排序(Heap Sort)
- PAT 1098. Insertion or Heap Sort (25) 堆排序和插入排序
- C:C的排序算法:堆排序(HeapSort)
- 堆排序-HeapSort
- 堆排序(HeapSort)的实现与应用
- 堆排序(HeapSort)
- 堆排序 heapsort(大根堆) c++
- 堆排序(heap sort)总结
- php堆排序(heapsort)练习
- 堆排序(heapsort)
- HeapSort 堆排序
- 堆排序(HEAPSORT)
- 堆积排序-堆排序-heap sort
- 堆排序 Heap Sort
- 堆排序(Heap Sort)
- PHP实现排序堆排序(Heap Sort)算法
- 堆排序(Heap Sort)
- [硕.Love Python] HeapSort(堆排序)
- java 数据结构之堆排序(HeapSort)详解及实例