堆排序(C語言實現)


一、堆的概念

         所謂堆,它是一個數組,也能夠被看成一個近似的全然二叉樹。樹上每一個結點相應數組的一個元素。二叉堆分為二種:最大堆和最小堆。本文主要介紹最大堆,最小堆類似。最大堆的特點:對於隨意某個結點,該結點的值大於左孩子、右孩子的值,可是左右孩子的值沒有要求。

二、堆排序算法

     首先,按堆的定義將數組R[0..n]調整為堆(這個過程稱為創建初始堆),交換R[0]R[n]

然后,將R[0..n-1]調整為堆,交換R[0]R[n-1]

如此反復,直到交換了R[0]R[1]為止。

以上思想可歸納為兩個操作:

1)根據初始數組去構造初始堆(構建一個完全二叉樹,保證所有的父結點都比它的孩子結點數值大)。

這里可以利用完全二叉樹的結構,從最后一個非終端節點開始對子元素進行排序篩選。

2)每次交換第一個和最后一個元素,輸出最后一個元素(最大值),然后把剩下元素重新調整為大根堆。

當輸出完最后一個元素后,這個數組已經是按照從小到大的順序排列了。

  具體圖片我就不找了,網上很多。

三、算法比較

堆排序算法的時間復雜度是O(nlgn),比插入排序要好,跟歸並排序相同,但是與歸並排序不一樣的地方在於,堆排序不需要額外的存儲空間,或者說,只需要常數個額外的存儲空間,屬於內排序算法。

 

#include <stdio.h>
#define N 1000
#define INF 999999999
int h[N];
//調整堆(迭代法)
//n:規模 i:二叉子堆的堆頂
void
heapAdjust(int n, int par)
{
    int tmp, pos, lc, rc;

    while (par <= n/2) {
        tmp = h[par]; //記錄父母結點鍵值
        lc = par<<1;
        rc = lc+1;
        pos = par;
        //父母結點至多更新2次
        if (h[par] < h[lc]) {
            h[par] = h[lc];
            pos = lc;
        }
        if (rc <= n && h[par] < h[rc]) {
            h[par] = h[rc];
            pos = rc;
        }
        if (pos == par) //無更新即無需調整
            break;
        else
            h[pos] = tmp;
        par = pos; //假設這個位置的結點是“父母結點”
    }
}

//創建堆
//規模為n的堆,對其父母結點,自底向上自右向左地調整堆
void
createHeap(int n)
{
    int i;

    for (i = n/2; i != 0; i--) {
        heapAdjust(n, i);
    }
}

void
heapSort(int n)
{
    int ntimes = n;

    while (ntimes--) {
        printf("%d\n", h[1]);
        h[1] = h[n];
        h[n--] = 0; //堆清零
        heapAdjust(n, 1);
    }
}

int
main(void)
{    
    int n, i;
    
    scanf("%d", &n);
    h[0] = INF;
    for (i = 1; i != n+1; i++) {
        scanf("%d", &h[i]);
    }
    createHeap(n);
    heapSort(n);
    return 0;
}

/*
  參考測試數據
6
342 31 52 626 12 124
10
43 525 14 21 52 3 52 45 319 15155
*/

 


免責聲明!

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



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