1. 程式人生 > >分治法之歸併排序(遞迴+分治)

分治法之歸併排序(遞迴+分治)

/*
歸併排序
思想:
1.分而治之,將一個無序的數列一直一分為二,直到分到序列中只有一個數的時候,這個序列肯定是有序的,因為只有一個數,然後將兩個只含有一個數字的序列合併為含有兩個數字的有序序列,這樣一直進行下去,最後就變成了一個大的有序數列
2.遞迴的結束條件是分到最小的序列只有一個數字的時候
時間複雜度分析:
最壞情況:T(n)=O(n*lg n)
平均情況:T(n)=O(n*lg n)
穩定性:穩定(兩個數相等的情況,不用移動位置
輔助空間:O(n)
特點總結:
高效
耗記憶體(需要一個同目標陣列SR相同大小的陣列來執行演算法)
*/
#include<stdio.h>
#define
max 1024 int SR[max],TR[max]; int merge(int SR[],int TR[],int s,int m,int t)//SR代表兩個有序序列構成的序列,s表示起始位置,m表示兩個序列的分解位置,但是SR[m]仍是屬於前面一個序列,t表示結束位置 {//TR是一個空陣列,用來存放排序好之後的數字 int i=s,j=m+1,k=s; while(i<=m&&j<=t) { if(SR[i]<SR[j]) { TR[k++]=SR[i++]; }
else { TR[k++]=SR[j++]; } } while(i<=m)//當前面一個序列有剩餘的時候,直接把剩餘數字放在TR的後面 { TR[k++]=SR[i++]; } while(j<=t)//當後面一個序列有剩餘的時候,直接把剩餘數字放在TR的後面 { TR[k++]=SR[j++]; } return 0; }//該函式要求SR是由兩個有序序列構成 void copy(int SR[],int TR[],int s,int t)//
把TR賦給SR { int i; for(i=s;i<t;i++) { SR[i]=TR[i]; } } int mergesort(int SR[],int s,int t) { if(s<t)//表示從s到t有多個數字 { int m=(s+t)/2;//將序列一分為二 mergesort(SR,s,m);//前一半序列繼續進行歸併排序 mergesort(SR,m+1,t);//後一半序列同時進行歸併排序, //以上遞迴呼叫的結束條件是s!<t,也就是進行分到只有一個數字進行歸併排序的時候,一個序列只有一個數字,那麼這個序列肯定是有序的 //以上都是屬於“分”的階段,目的是獲得兩個有序的數列 merge(SR,TR,s,m,t);//對這兩個有序的數列,進行排序,變成一個同樣大小但是有序的數列 copy(SR,TR,s,t);//將在TR中排序好的數列給SR,方便SR遞迴呼叫歸併排序,因為每次兩個歸併排序的結果都是儲存在TR中的,現在要進行下一步就必須在TR數列的基礎上面=進行,所以我們把TR給SR }else//表示從s到t只有一個數字(s==t),或者沒有數字(s>t) { ;//空,也可省略,加一個else只是為了更好的理解程式 } return 0; } int main() { int n; printf("請輸入排序數字的個數:\n"); scanf("%d",&n); int i; for(i=0;i<n;i++) { scanf("%d",&SR[i]); } mergesort(SR,0,n-1);//升序排列 for(i=0;i<n;i++) { printf("%d ",SR[i]); } printf("\n"); return 0; }

技術在於分享