排序算法之(7)--堆排序

介紹

堆排序(Heap Sort)就是利用堆(假設利用大頂堆)進行排序的方法。它的基本思想是,將待排序的序列構造成一個大頂堆。此時,整個序列的最大值就是堆頂的根結點。將它移走(其實就是將其與堆數組的末尾元素交換,此時末尾元素就是最大值),然後將剩餘的n-1個序列重新構造成一個堆,這樣就會得到n個元素中的次小值。如此反覆執行,便能得到一個有序序列了。

堆排序真的是一個好東西,不管是待排序序列有序無序,時間複雜度都基本一樣。

注:這裏堆是一種數據結構,而非內存的那個堆。可以參考完全二叉樹,可以表示成一個數組。
這裏寫圖片描述


代碼

//堆排序
/*
這個堆是數據結構堆,不是內存malloc相關的那個堆--我曾經理解錯n久
根節點比孩子節點都大的叫大頂堆(包括子樹的根),比孩子節點小的叫小頂堆
從小到大排序用的是大頂堆,所以要先構造這種堆,然後把這個根的最大元素交換到最尾巴去
每次拿走一個最大元素,待排序的隊列就慢慢變短
主要步驟1,初始化構造這種大頂堆,把堆頂最大的數放到最尾巴,數列長度減少1,再次構建大頂堆
2,這時候只有堆頂元素不滿足大頂堆,那麼其實只要從堆頂元素開始慢慢微調而已,沒必要再完全重新建堆,想要也可以,不過很浪費時間
理解起來確實很難,涉及到完全二叉樹
孩子節點i的爸爸是i/2,爸爸節點的兒子是2i和2i+1。
第一次初始化之後充分利用子樹已經是大頂堆
*/
//輔助函數:交換兩個變量
void swap(int*a,int*p)
{
    int temp = *a;
    *a = *p;
    *p = temp;
}

void adjust(int* arr,int len,int index)
{
    //調整函數,把孩子、父親中的最大值放到父親節點
    //index爲待調整節點下標,一開始設它最大
    int max = index;
    int left = 2*index+1;//左孩子
    int right = 2*index+2;//右孩子
    if(left<len && arr[left] > arr[max])
    {
        max = left;
    }
    if(right<len && arr[right] > arr[max])
    {
        max = right;
    }
    //如果父親節點不是最大
    if(max!=index)
    {
        //一旦上層節點影響了某個孩子節點,還要觀察以這個孩子節點爲父節點的子樹是不是也不是大頂堆了
        swap(&arr[index],&arr[max]);
        //因爲發生了交換,還要繼續調整受到影響的孩子節點
        //***************************************
        adjust(arr,len,max);//這句話非常非常關鍵
        //***************************************
        /*
            只有父親和孩子節點發生了交換,纔有繼續調整孩子的必要,如果無腦在不是這裏面遞歸,堆排序的效果不會比冒泡好到哪去
            而如果寫在了這裏面,雖然還是pk不過快排,但好歹和快排的差距只縮小到個位數倍數的量級(小數據量的時候)
            堆排序一個優點是空間複雜度也不高
        */
    }
}
//主要排序部分
void heapSort(int* arr,int len)
{
    //初始化大頂堆
    //initHeap(arr,i,0);
    //從最後一個非葉子節點開始
    //第一次一定要從下至上一直排,一開始是亂序的
    int i = len/2-1;
    for(i;i>=0;i--)
    {
        adjust(arr,len,i);
    }
    swap(&arr[0],&arr[len-1]);


    //第二次之後,只需要從根節點從上到下調整,遇到沒發生交換的直接可以退出循環了
    //微調得到大頂堆(因爲只有堆頂不滿足而已)
    int j = len -1; //去掉尾節點後的數組長度
    //把最大值交換到最後
    for(j;j>0;j--)
    {
        adjust(arr,j,0);
        swap(&arr[0],&arr[j-1]);
    }
}
發佈了96 篇原創文章 · 獲贊 100 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章