堆排序

        堆是一種完全二叉樹,分爲小根堆和大根堆。大根堆中任意節點的值都不大於其父節點的值。有些類似於二叉搜索樹,都是要求父節點和子節點的值滿足某種關係。

        堆排序的基本思想是,先用所給數據建立大根堆,堆頂元素即爲最大值,將其與最後一個元素交換,此時最後一個元素爲最大值;再對最大值之前的元素進行調整,使其恢復爲大根堆。再如此將次大值取出排列在最大值之前,循環往復,直到所有元素都排好序。

        於是,排序的關鍵就是建堆和調整。如下HeapAjust函數實現調整樹的功能,使其滿足堆的性質。算法是:從一個指定節點開始,如果某個節點的值小於其子節點的值,就將其與較大的子節點交換,以使當前父節點與子節點滿足堆的性質;然而,進行調整後,以被交換的子節點爲根的子樹可能又不滿足堆的性質了,因此需要繼續向下迭代遍歷,直到當前節點滿足堆的性質,就退出循環。

        這是調整函數,想要建立堆,需要從最後一個非葉節點開始,自底向上調用此函數。堆排序時,每次取出堆中的最大元素後,要對剩下的元素進行調整,以維持堆的性質。直到所有節點都已取出,完成排序。

這是百度百科中調整函數、堆排序函數及測試代碼:

#include <stdio.h>

//array是待調整的堆數組,i是待調整的數組元素的位置,nlength是數組的長度
//本函數功能是:調整以第i個節點(即值爲array[i]的節點)爲根節點的樹,使其成爲大根堆 
void HeapAdjust(int array[], int i, int nLength)
{
    int nChild;
    int nTemp;
    
    for(; 2*i+1 < nLength; i=nChild)
    {
        //子結點的位置=2*(父結點位置)+1
        nChild = 2*i+1;
        
        //得到子結點中較大的結點
         if(nChild < nLength-1 && array[nChild+1] > array[nChild])
            ++nChild;
            
        //如果較大的子結點大於父結點那麼把較大的子結點往上移動,替換它的父結點
         if(array[i] < array[nChild])
        {
            nTemp=array[i];
            array[i]=array[nChild];
            array[nChild]=nTemp; 
        }
        else 
             break; //否則退出循環
    }
}   
//堆排序算法
void HeapSort(int array[], int length)
{
    int i, j;
    
    //建堆 
    //調整序列的前半部分元素,調整完之後第一個元素是序列的最大的元素
    //length/2-1是最後一個非葉節點,此處"/"爲整除
    for(i=length/2-1; i>=0; --i)
    {
        HeapAdjust(array, i, length);
    }
    
    //從最後一個元素開始對序列進行調整,不斷的縮小調整的範圍直到第一個元素
     for(i=length-1; i>0; --i)
    {
        //把第一個元素和當前的最後一個元素交換,
         //保證當前的最後一個位置的元素都是在現在的這個序列之中最大的
         array[i] = array[0]^array[i];
        array[0] = array[0]^array[i];
        array[i] = array[0]^array[i];
        
        //不斷縮小調整heap的範圍,每一次調整完畢保證第一個元素是當前序列的最大值
         HeapAdjust(array,0,i);
    }
}

int main()
{
    int i;
    int num[]={0,1,2,3,4,5,6,7,8,9};
    
    HeapSort(num, sizeof(num)/sizeof(int));
    
    for(i=0; i < sizeof(num)/sizeof(int); i++)
    {
        printf("%d ",num[i]);
    }
    
    printf("\n");
        
    return 0;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章