java排序--堆排序

一.简介

       上一篇讲了快速排序,这一篇来讲讲堆排序。堆可以借助借助完全二叉树来理解,数值排列按照广度优先算法输出的顺序给出。堆排序分按大堆排序和小堆排序。堆排序就是一趟排序完,最大的值在最前面;而按小堆排序就是一趟排序完,最小的值在最前面。

       排序过程为使记录序列按关键字非递减有序排序,则在堆排序的算法中,先建一个“大顶堆”,即先选得一个关键字为最大的记录并与序列中最后一个记录交换,然后对序列的前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比较大的文件还是很有效的。此外它是不稳定的排序。

猜你喜欢

转载自blog.csdn.net/u011381576/article/details/80145648