資料結構實驗之排序四:尋找大富翁(SDUT 3401)
阿新 • • 發佈:2018-12-16
#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; }