常用數據結構算法 : 堆排序


  在一次面試當中,面試官問到了自己關於堆排序的一些細節,之前在整理各種高級排序的時候,有看過堆排序,然而在現場要給面試官講解排序的原理的時候,發現自己懵逼了,所以還是需要特地寫一篇隨筆來記錄堆排序的整個原理和過程,這里借鑒了百度知道里頭的堆排序的講解圖。

  首先我們要了解什么是堆排序,其排序的時間復雜度為O(nlogn),且不會因為排序的數組的數據惡化,但需要提供額外的排序內存。這里的堆當中,常用的數據結構就是二叉樹,且是完全二叉樹。根據要排序的方式(升序,降序)可以將這個二叉樹的特點定義下來,就是根節點都比左右子節點大(大根堆)或者是根節點都比左右子節點小(小根堆)。而整個堆排的過程,包括了一個建樹,調整樹頂的過程。二話不說,先舉一個例子來說,假定我們要對序列{16,7,3,20,17,8}進行排序,先上我們的流程圖:

這是初步構建出來的樹,之后,我們從葉子節點開始從底向上遍歷,調整樹當中的數據,使其成為大根堆:

通過對圖中畫紅圈的節點進行數據交換,我們可以得到構建出來的大根堆:

之后我們將根節點和最后一個葉子節點互換,並且將互換后的這個葉子節點固定住(表示這個點已經被排序好)之后調整樹的時候不對該再進行調整。

之后的過程依次類推,最后就可以得到一個排序好的數組。

整個流程通過圖可以看的很清晰。那么接下來我們來看看代碼實現:

public class testHeapSort {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] input={2,3,5,2,3,6,7,4,6};
        HeapSort(input);
        for(int tmp:input)
            System.out.print(tmp+" ");
    }
    
    //堆排序
    public static void HeapSort(int array[])
    {
        buildTheTree(array);
        
        //從數組當中最后一個位置開始固定,一次固定到頭,即可得到升序數組
        for(int i=array.length-1;i>=1;i--)
        {
            //根和當前最后的葉子節點交換
            int tmp=array[0];
            array[0]=array[i];
            array[i]=tmp;
            
            //調整堆
            maxify(array, i, 0);
        }
    }
    
    //第一次建樹
    public static void buildTheTree(int array[])
    {
        //因為是從葉子節點開始從底向上的調整,所以起點為數組長度的2分之一
        int half=array.length/2;
        
        for(int i=half;i>=0;i--)
        {
            maxify(array, array.length, i);
        }
        
    }
    
    //調整樹的方法,大頂堆
    public static void maxify(int array[],int size,int i)
    {
        //左子節點
        int left=2*i+1;
        //右子節點
        int right=2*i+2;
        
        //找出當前根節點、其左子節點、右子節點最大的節點作為根節點
        int large=i;
        if(left<size && array[left]>array[i])large=left;
        if(right<size && array[right]>array[large])large=right;
        
        //如果再上邊查找過程當中,根節點就是最大的節點,那么不需要再去調整樹,因為這是一個從下往上調整的過程
        //所以當前節點以下的樹已經滿足大根堆的要求,直接返回
        if(large==i)return;
        
        //如果需要當前根節點和子節點互換,則互換過去的子節點再一次調整
        int tmp=array[large];
        array[large]=array[i];
        array[i]=tmp;
        //互換后調整。
        maxify(array, size, large);
    }
}

通過代碼當中的注解,結合流程圖應該就可以很清晰的理解堆排序的原理和實現過程,這里就不再進行贅述了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM