美文网首页数据结构与算法
算法(一)之排序算法(八)——堆排序(HeapSort)

算法(一)之排序算法(八)——堆排序(HeapSort)

作者: bryanrady_wang | 来源:发表于2017-12-21 12:49 被阅读13次

    今天我们来介绍八大排序算法之中的最后一种,堆排序。堆排序是指利用堆积树(堆)这种 数据结构所设计的一种排序算法,它是选择排序的一种。

    这些概念我觉得是不用太过领会的,我们只需要记住几个特点,就可以实现堆排序了.

    堆实际上是一棵完全二叉树,其任何一非叶节点满足性质:

        Key[i] <= key[2i+1] && Key[i] <= key[2i+2] 或者 Key[i] >= Key[2i+1] && key>=key[2i+2]
    

    即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字。堆分为大顶堆和小顶堆,

    满足      Key[i]  >=  Key[2i+1]  &&  key  >=  key[2i+2]  称为大顶堆,
    
    满足     Key[i]  <=  key[2i+1]  &&  Key[i]  <=  key[2i+2]  称为小顶堆。
    

    由上述性质可知大顶堆的堆顶的关键字肯定是所有关键字中最大的,小顶堆的堆顶的关键字是所有关键字中最小的。

    我们下面演示小顶堆排序的过程:

    (1)从最后一个非叶子节点开始,每三个节点做一次大小比较,最小的做根,如果移动过程中如果子树上的顺序被破坏了,子树上重新调整三个节点的位置。

    (2)取走整个树的根节点,把最后一个叶子作为根节点。

    (3)重复(1)和(2)的过程,知道树中的所有节点全部被取走为止。

    下面举例说明:

    给定一个整形数组a[]={6, 3, 9, 2, 4, 5, 1, 8, 7},对其进行堆排序。首先根据该数组元素构建一个完全二叉树,得到

    然后我们对这棵完全二叉树进行堆排序过程:

    堆排序(1).png

    上图中是完成了一次建堆操作,从最后一个非叶子节点开始一直到根节点,完成建堆操作。

    堆排序(2).png 堆排序(3).png 堆排序(4).png 堆排序(5).png 堆排序(6).png 堆排序(7).png

    到了这里我不想继续往下面画了,因为大家可能看了上面就已经知道结果了,省略了最后2张图。

    自己做的图画的不是太好,下次会改进。从上面的图我们可以看出,小顶堆的排序过程就是每次建堆都把最小的数找到最后放在根节点的位置,这样我们每次只要从根节点拿出数据,就可以得出排序结果了。

    下面我们来看下代码实现:

      public static void heapSort(int[] array){
        int n = array.length;   //堆中元素的个数
       //对整个数组建堆,从最后一个非叶子节点(array.length-1)/2开始建堆,一直到根节点
        for(int i=(array.length-1)/2;i>=0;i--){
            createHeap(array,n,i);
        }
    
        while (n>0){
            System.out.print(array[0]+" ");     //输出根节点
            array[0] = array[n-1];      //把最后一个节点放到根节点上
            n--;
            createHeap(array,n,0);      //从根节点开始重新建堆
        }
    }
    
    public static void createHeap(int[] array,int n,int k){
        int kLeft = 2*k + 1;    //k的左孩子的下标
        int kRight = 2*k + 2;   //k的右孩子的下标
        if(kLeft>=n && kRight>=n){    //如果两个下标都越界,表示没有左右孩子
            return;
        }
    
        int kLeftValue = Integer.MAX_VALUE;     //如果是最大值,代表没有左孩子
        int kRightValue = Integer.MAX_VALUE;
        if(kLeft<n){
            kLeftValue = array[kLeft];
        }
        if(kRight<n){
            kRightValue = array[kRight];
        }
    
        //对三个节点比较大小
        if(array[k]<kLeftValue && array[k]<kRightValue){    //如果左右孩子都比k小,则不用建堆,直接返回
            return;
        }
        if(kLeftValue < kRightValue){   //如果左孩子比右孩子小,就用左孩子和k交换
            int temp = array[k];
            array[k] = array[kLeft];
            array[kLeft] = temp;
            createHeap(array,n,kLeft);      //为了防止交换数字后破坏树中的堆结构,必须要重新建堆
        }else{
            int temp = array[k];
            array[k] = array[kRight];
            array[kRight] = temp;
            createHeap(array,n,kRight);
        }
    }
    

    堆排序的应用:当数据为无序或链式结构的时候进行二分查找。一般不用来排序,安卓代码用不到,使用在大数据的查找,一般写在后台, 虽然不常用但是我们还是应该了解一下的。

    到了这里八大排序我们就基本讲完了,这也是对我学习过程的一个总结,如果有哪里写错了,请大家指点。

    相关文章

      网友评论

        本文标题:算法(一)之排序算法(八)——堆排序(HeapSort)

        本文链接:https://www.haomeiwen.com/subject/kdzowxtx.html