#include <stdio.h> #include <stdlib.h> #include <string.h> void Swap(int a[], int i, int j) // 交換函數 { int t = a[i]; a[i] = a[j]; a[j] = t; } void HeapMerge(int *a,int i,int n) //調整函數,也是核心地方 // 如下的樹的概念都是把這個堆轉變成樹來講的 { int lc = 2*i; // 由於咱們用一位數組存放的,這裏下標從1開始,若是1存放根結點,那麼左紫薯就是2×i 右紫薯是 2 × 1 + 1 int rc = 2*i+1; // 由於堆排序這裏是一顆徹底二叉樹,層次遍歷這個樹,而後依次放進這個下標從1開始的數組中,獲得的就是以上結果了 int k = i; //存放當前調整的結點的下標 if(i <= n/2) //若是大於n/2,就是葉子結點了,就不須要再調整了 { if(lc <= n && a[lc] > a[k]) // 左子樹的比較 { k = lc; } if(rc <= n && a[rc] > a[k]) // 右紫薯的比較 這樣子就是選的左右紫薯中大的那個了 { k = rc; } if(k != i) // 若是找到了它的左右紫薯中比它大的 { Swap(a,i,k); // 交換這兩個值 HeapMerge(a,k,n); // 繼續把k這個位置的數,也就是上一步中爲交換前的a[i],往下調整,要保證左右紫薯都小於根節點 } } } void HeapCreat(int *a,int n) { for(int i=n/2; i>=1; i--) { HeapMerge(a,i,n); // 從第一個非葉子結點開始調整樹,n/2就是第一個非葉子結點,徹底二叉樹的性質決定的。 } } void HeapSort(int *a,int n) { int i; HeapCreat(a,n); //先調整好樹,讓成爲一個大頂堆 for(i=n; i>=1; i--) { Swap(a,1,i); // 把這個堆頂,也就是最大的,放到最後 HeapMerge(a,1,i-1); // i - 1 也就是剩下的再從新調整 // 直到所有完成,層次遍歷樹變成有序序列,對應的數組就是有序數組 } } int main() { int n,m,p,t, Min; while(scanf("%d %d",&n,&m)!=EOF) { int a[12]; p = 1; for(int i = 0; i < n; i++) // 這個題的緣由,不能所有輸入,對於所有的數建堆 { scanf("%d",&t); if(p < m + 1) a[p++]=t; else { Min = 1; for(int j = 2; j < p; j++) { if(a[Min] > a[j]) Min = j; } if(a[Min] < t) a[Min] = t; } } //挑出來前 m 大的數 HeapSort(a,m); // 堆排 for(int i = m; i >= 1; i--) if(i==m) printf("%d",a[i]); else printf(" %d",a[i]); printf("\n"); } return 0; }