首頁 > 軟體

C語言資料結構之堆排序詳解

2022-03-10 13:01:21

1.堆的概念及結構

如果有一個關鍵碼的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二元樹(二元樹具體概念參見——二元樹詳解)的順序儲存方式儲存在一個一維陣列中,並滿足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,則稱為小堆(或大堆)。將根節點最大的堆叫做最大堆或大根堆,根節點最小的堆叫做最小堆或小根堆。

堆的性質:

  • 堆中某個節點的值總是不大於或不小於其父節點的值;
  • 堆總是一棵完全二元樹。

2.堆的實現

堆的實現請參見——二元樹詳解(堆的實現)

2.1 堆的向下調整演演算法

(此文章都已建小堆為例)

向下調整演演算法前提:當前樹左右子樹都是小堆

核心思想:選出左右孩子中小的那個,和父親交換,小的往上浮,大的往下沉,這裡是小堆,如果是大堆則相反。

程式碼實現

void swap(int *x, int *y)
{
    int temp = *x;
    *x = *y;
    *y = temp;
}
//堆向下調整演演算法
void AdjustDown(int *a, int n, int root)
{
    int parent = root;
    int child = parent * 2 + 1;
    while (child<n)
    {
        //保證孩子節點child為兩個孩子中的最小值;保證不越界
        if (a[child] > a[child + 1] && child+1 < n)
            ++child;
        if (a[child] < a[parent])
        {
            swap(&a[child], &a[parent]);
            parent = child;
            child = parent * 2 + 1;
        }
        else
            break;
    }
}

2.2 堆的向上調整演演算法

使用場景:向上調整演演算法適用於向堆中插入資料,當向堆中插入資料就可能會導致堆失去大堆或者小堆的性質,此時需要重新調整,向上調整的思路與向下調整演演算法的思路類似,向上調整演演算法只需要從插入結點位置開始和父節點比較。

圖示:

程式碼實現:

void AdjustUp(int *a, int child)
{
    int parent = (child - 1) / 2;
    while (child > 0)
    {
        if (a[parent] > a[child])
        {
            swap(&a[parent], &a[child]);
            child = parent;
            parent = (child - 1) / 2;
        }
        else
            break;
    }
}

2.3 建堆(陣列)

從最後一個非葉子節點位置行依次開始調整,如圖:

程式碼實現:

int parent = (n-2) / 2;
    //首先對每一個非葉子節點進行一次向下調整演演算法,保證每個非葉子節點的
    //孩子都小於它的父節點,然後可得到最小值,就在堆的頂端的父節點(也叫做建小堆)
    while (parent >= 0)
    {
        AdjustDown(a, n, parent);
        --parent;
    }

2.4 堆排序

升序建大堆,降序建小堆

void HeapSort(int *a, int n)
{
    int parent = (n-2) / 2;
    //首先對每一個非葉子節點進行一次向下調整演演算法,保證每個非葉子節點的
    //孩子都小於它的父節點,然後可得到最小值,就在堆的頂端的父節點(也叫做建小堆)
    while (parent >= 0)
    {
        AdjustDown(a, n, parent);
        --parent;
    }
    int end = n-1;
    while (end>0)
    {
        //將堆頂的數與最後的end,以此迴圈,進行交換就可得到有序序列
        //注意:建小堆,得到降序序列
        swap(&a[end], &a[0]);
        AdjustDown(a, end, 0);
        --end;
    }
}

2.5 堆排序的時間複雜度

所以建堆時間複雜度為O(N);

向下調整演演算法時間複雜度 O(logN);

所以堆排序的時間複雜度為 O(N*logN)

以上就是C語言資料結構之堆排序詳解的詳細內容,更多關於C語言堆排序的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com