堆排序只需要記錄乙個記錄大小的輔助空間,每個待排序的記錄僅占有乙個儲存空間。
**堆的定義:**n個元素的序列
當且僅當滿足如下關係時,稱之為堆。 ⎧⎩
⎨ki≤
k2ik
i≤k2
i+1
或 ⎧⎩⎨
ki≥k
2iki
≥k2i
+1(i = 1,2,3,…,[n
2])若將和此序列對應的一維陣列看成是乙個完全二叉樹,則堆的含義表明,完全二叉樹中所有非終端節點的值均不大於其左、右孩子結點的值。由此,若序列
是堆,則堆頂元素必定為序列中n個元素的最小值(或最大值)。
例如序列{96,83,27,38,11,09}和對應的完全二叉樹為:
若在輸出堆頂的最小值之後,使得剩餘n-1個元素的序列重又建成乙個堆,則得到n個元素中的次小值。如此反覆執行,便能得到乙個有序序列,這個過程稱之為堆排序。
如下圖所示,假設輸出堆頂元素之後,以堆中最後乙個元素替代,此時根結點的左、右子樹均為堆,則僅需自上至下調整即可。首先以堆頂元素和其左、右子樹根結點的值進行比較,由於右子樹根結點的值相愛哦與左子樹結點的值,則將27和97交換,由於97的替代了27之後破壞了右子樹的堆,則需進行和上述相同的調整,直至葉子結點,此時堆頂為n-1個元素中的最小值。重複上述過程,將堆頂元素27和堆中最後乙個元素97交換且調整,得到乙個新的堆。我們稱這個自堆頂至葉子的調整過程為篩選。
從乙個無序序列建堆的過程就是乙個反覆篩選的過程。若將次序列看成是乙個完全二叉樹,則最後乙個非終端結點是第[n
2]個元素,由此篩選只需從第[n
2]個元素開始。
例如下圖中的二叉樹表示乙個有8個元素的無序序列,則篩選從第4個元素開始,由於97>49,則交換之。同理,在第3個元素65被篩選之後序列的狀態如圖所示。由於第2個元素38不大於其左、右子樹根的值,則篩選後的序列不變。
基本演算法思想:使記錄序列按關鍵字非遞減有序排列,則在堆排序的演算法中先建立乙個最大堆,即先選得乙個關鍵字為最大的記錄並與序列中最後乙個記錄交換,然後對序列中前n-1記錄進行篩選,重新將它調整為乙個最大堆,如此分那副直至排序結束。
#include
#define eq(a,b) ((a)==(b))
#define lt(a,b) ((a)
#define lq(a,b) ((a)<=(b))
#define n 8
#define maxsize 20 /* 乙個用作示例的小順序表的最大長度 */
typedef
int infotype; /* 定義其它資料項的型別 */
typedef
int keytype; /* 定義關鍵字型別為整型 */
typedef
struct
redtype; /* 記錄型別 */
typedef
struct
sqlist; /* 順序表型別 */
typedef sqlist heaptype; /* 堆採用順序表儲存表示 */
void heapadjust(heaptype *h,int
s,int
m) /* 演算法10.10*/
(*h).r[s]=rc; /* 插入 */
} void heapsort(heaptype *h)
}
void print(heaptype h)
void main()
,,,,,,,};
heaptype h;
int i;
for(i=0;i1]=d[i];
h.length=n;
printf("排序前:\n");
print(h);
heapsort(&h);
printf("排序後:\n");
演算法筆記 堆排序
堆排序是一種原地的,時間複雜度為 o nlogn 的排序演算法。快速排序的時間複雜度也是 o nlogn 甚至堆排序比快速排序的時間複雜度還要穩定,但是快速排序的效能要比堆排序好。什麼是堆 堆是乙個完全二叉樹。堆上任一節點的值都大於等於它的左右子樹的值,或者小於等於它的左右子樹的值。對於每個節點大於...
堆排序學習筆記
參考此文的學習筆記 不用交換,則已經是最大堆,不用迴圈了 else break void sort int a,int length 開始排序,排序是從上到下從左到右的調整 for int j length 1 j 0 j int main sort a,length for int i 0 i l...
暑假筆記 堆排序
原題位址 題目描述 有n個函式,分別為f1,f2,fn。定義fi x aix 2 bix ci x n 給定這些ai bi和ci,請求出所有函式的所有函式值中最小的m個 如有重複的要輸出多個 輸入輸出格式 輸入格式 輸入資料 第一行輸入兩個正整數n和m。以下n行每行三個正整數,其中第i行的三個數分別...