一.简介
上一篇讲了快速排序,这一篇来讲讲堆排序。堆可以借助借助完全二叉树来理解,数值排列按照广度优先算法输出的顺序给出。堆排序分按大堆排序和小堆排序。堆排序就是一趟排序完,最大的值在最前面;而按小堆排序就是一趟排序完,最小的值在最前面。
排序过程为使记录序列按关键字非递减有序排序,则在堆排序的算法中,先建一个“大顶堆”,即先选得一个关键字为最大的记录并与序列中最后一个记录交换,然后对序列的前n-1记录进行筛选,重新将它调整为一个“大顶堆”,如此反复直至排序结束。
排序过程:
由于事先选用的数据结构为数组,所以给下数组的排序过程
假设数组数值为
5,2,6,3,7,9,10,4,8
那么它在第一次大堆排序之后的结果为
10,8,9,4,7,5,6,2,3
二.代码实现
public class HeapSort { public static void main(String[] args) { int a[] = {5, 2, 6, 3, 7, 9, 10, 4, 8}; heapSort(a); print(a); } /** * 打印数组 * * @param a */ private static void print(int[] a) { for (int i = 0; i < a.length; i++) { System.out.print(a[i] + " "); } System.out.println(); } /** * 按大堆排序 * * @param a 数组 * * @param s 排序的索引 * * @param length 数组的长度 */ static void heapAdjust(int[] a, int s, int length) { int key = a[s]; for (int j = 2 * s + 1; j <= length; j = j * 2 + 1) { if (j < length && (j + 1) < length && a[j] < a[j + 1]) //如果有左右节点,需要找出最大那个值的索引 j++; if (key > a[j]) { //如果比较关键字的大于后续数组值,直接跳出需要,说白了,此刻记录的还是当前索引值是最大值 break; } a[s] = a[j]; //需要将这趟最大的赋值到前面的索引里面 s = j; // 更新当前索引 } a[s] = key; //将关键字赋值到最后变更的索引处 } /** * 堆排序 * * @param a 数组 */ static void heapSort(int[] a) { for (int i = a.length / 2 - 1; i >= 0; --i) { //第一趟 按大堆排一次 heapAdjust(a, i, a.length); //按大堆排序 } for (int i = a.length - 1; i > 0; i--) { int temp = a[0]; a[0] = a[i]; a[i] = temp; //由于之前是按大堆排序的,这样交换一下就可以得到从小到大的顺序 heapAdjust(a, 0, i - 1); //每排序完一次,长度需要减1 } } }
注释代码上面已经写的很清楚了,结果:
2 3 4 5 6 7 8 9 10
三.总结
就平均时间而言,堆排序也是nlog(n)。堆排序方法对记录数较少的文件并不值得提倡,但是对n比较大的文件还是很有效的。此外它是不稳定的排序。