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

  在一次面試當中,面試官問到了本身關於堆排序的一些細節,以前在整理各類高級排序的時候,有看過堆排序,然而在現場要給面試官講解排序的原理的時候,發現本身懵逼了,因此仍是須要特意寫一篇隨筆來記錄堆排序的整個原理和過程,這裏借鑑了百度知道里頭的堆排序的講解圖。面試

  首先咱們要了解什麼是堆排序,其排序的時間複雜度爲O(nlogn),且不會由於排序的數組的數據惡化,但須要提供額外的排序內存。這裏的堆當中,經常使用的數據結構就是二叉樹,且是徹底二叉樹。根據要排序的方式(升序,降序)能夠將這個二叉樹的特色定義下來,就是根節點都比左右子節點大(大根堆)或者是根節點都比左右子節點小(小根堆)。而整個堆排的過程,包括了一個建樹,調整樹頂的過程。二話不說,先舉一個例子來講,假定咱們要對序列{16,7,3,20,17,8}進行排序,先上咱們的流程圖:數組

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

經過對圖中畫紅圈的節點進行數據交換,咱們能夠獲得構建出來的大根堆:ui

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

以後的過程依次類推,最後就能夠獲得一個排序好的數組。code

整個流程經過圖能夠看的很清晰。那麼接下來咱們來看看代碼實現:blog

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);
    }
}

經過代碼當中的註解,結合流程圖應該就能夠很清晰的理解堆排序的原理和實現過程,這裏就再也不進行贅述了。排序

相關文章
相關標籤/搜索