堆排序是几种排序中比较难理解的一点,开始学数据结构的时候有些浑浑噩噩,原理没搞清楚了就看代码,越搞越糊涂,也越困,加之那时候大学,没意识到良好的算法基础意味着什么,所以直到快毕业基础数据结构和算法都是一塌糊涂,找工作时候才耐下性子看了下,如今工作一年了,面对着惨淡的工作环境和薪资,让我有种学习的动力,如果你跟我一样苦逼,那就抽时间好好打打基础吧。
我是比较追求简洁明了的那种,所以给出的代码基本上是比较好理解的,因为难理解的我理解不了,也就没办法对照代码看懂验证或者是写出来。理解堆排序一定要记得是用完全二叉树的性质来对数组元素进行排序,是一种思想,而不是建一颗完全二叉树排序。
废话不多说,看下堆的定义(十本书基本一样,这里摘自wiki)
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆性质:即子结点的键值或索引总是小于(或者大于)它的父节点。wiki上面有很多很好的资料,如果有条件尽量看英文的,一般都能看懂,如果看了wiki后还不明白可以google,这些常用的算法总会找到一个让你能看懂的。
package com.mars.sort; public class HeapSortWiki { private void siftDown(int[] a, int start, int end){ int root = start; //child 孩子节点,swap 要交换的节点 int child, swap; //while root has at least one child while(root * 2 + 1 <= end){ child = root * 2 + 1; //初始将根节点作为需要交换的节点,如果根节点跟左右子节点 //比较后,swap == root则说明不需要调整,则表明该子树 //是一个小根堆,无需调整 swap = root; //检查根节点是否小于左子树 if(a[swap] < a[child]){ swap = child; } //这里有个技巧,如果左节点大于父节点,那么这里比较的是 //左右节点,否则是父节点和右节点比较 if(a[swap] < a[child + 1]){ swap = child + 1; } //检查是否需要交换 swap == root说明已经是一个小堆了, //不需再做调整 if(swap != root){ int tmp = a[root]; a[root] = a[swap]; a[swap] = tmp; }else{//swap == root说明已经是一个小堆 return; } } } /** * 从树的最底层检查是否满足堆的属性 * @param a * @param count */ private void heapify(int[] a, int count){ //从最后一个父节点开始 int start = (count - 2) / 2; while(start >= 0){ //sift down the node at index start to //the proper place such that all nodes //below the start index are in heap order siftDown(a, start, count - 1); start -= 1; } } public void heapSort(int[] a, int count){ heapify(a, count); int end = count - 1; while(end > 0){ int tmp = a[end]; a[end] = a[0]; a[0] = tmp; end -= 1; heapify(a, end); } } public static void main(String[] args) { int a[] = {1, 0, 4, -1, 5, 2, 6, 9, 8, 7, 3}; new HeapSortWiki().heapSort(a, 11); for(int b : a){ System.out.print(b + " "); } } }
http://www.cnblogs.com/zabery/archive/2011/07/26/2117103.html
http://en.wikipedia.org/wiki/Heapsort