堆排序學習

數據結構中的堆的定義:一組關鍵字序列稱爲堆,這組序列按照編號可以排成一顆完全二叉樹,並且這棵完全二叉樹必須滿足雙親節點一定大於等於孩子節點的關鍵字值。(只考慮大頂堆)。堆一般用於數據的排序,並且只適用於順序表,其他線性表或其他數據結構無法保證關鍵字序列能按照先後順序排在一棵完全二叉樹裏。

給定一組關鍵字序列,要對它進行排序,最關鍵的是創建初始化堆,經過這個初始化的過程就可以使這組序列裏面關鍵字最大的數據排到了堆頂,然後這時互換堆頂元素和堆最後一個元素的位置,讓關鍵字最大的元素排到最後面。再將堆的元素個數減少1,並重新對減少容量後的堆進行篩選,將新堆中最大的元素排到堆頂的位置,接着互換新堆裏堆頂和最後的元素。重複以上步驟,既可以將序列按照遞增的方式排列在一棵完全二叉樹內,當然原來這組序列是用順序表存儲的,自然該順序表也會被排好序。

例:

下面的序列:D[9],D[0]不存儲數據,用於保存中間值

0 1 2 3 4 5 6 7 8
  49 38 65 97 76 13 27 49

算法如下:C語言

調整爲堆的篩選函數:

void  HeapAdjust(int D[],int s,int m)//D[]爲序列數組,s剛開始指向最後一個節點的雙親節點,m始終指向要轉成堆的二叉樹的最後一個節點
{//下面提到的指針不是狹義的指針變量的那種指針,只是對某一元素的位置的指向,就是數據的下標
int j;
D[0] = D[s];//先把s指針裏的元素拿出來,用D[0]保存起來
for (j = 2 * s; j  <= m ; j *= 2)//指向s指針的孩子節點,可以循環的話,j將指向原來j的左孩子節點,s將指向原來的j,D[s]與D[j]
//仍爲雙親節點與孩子節點的關係,當然j *= 2之後超出了節點範圍,循環也就終止了。
{
if(j < m && D[j] < D[j + 1])
   j ++;//使j指向s孩子節點中較大的那個
if(D[0] >= D[j]) break;//此時s節點下面都滿足堆的定義,循環終止
D[s] = D[j];//因爲s的孩子節點比s大,所以將孩子節點升至s的位置,同時不能保證s一定比j下面的元素大,所以要循環找到合適的位置插入s,同時比s大的就應該上浮,這裏說的s是D[0]裏面保存的s,因爲後面的s是會變的
s = j;//s指向j的位置,下一步j * = 2;
}
D[s] = D[0];
}
利用堆排序的函數:
void HeapSort(int D[],int L)//L爲數組的長度
{
int i;
for (i = L / 2;i > 0;i--)
    HeapAdjust(D,i,L);//創建初始化堆
for (i = L ;i> 1; i--)
{
D[0] = D[1];
D[1] = D[i];
D[i] = D[0];
HeapAdjust(D,1,i-1);//由於交換後打亂了原來堆的排序,所以需要重新篩選,使除最後一個元素之外的數據滿足堆的定義,同時由於,只是第一個元素影響了堆的定義所以只需要調整D[1]的位置,所以是HeapAdjust(D,1,i-1)。
}
}

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