二路歸併排序(未完)
阿新 • • 發佈:2018-12-15
注:歸併演算法是典型的分治法例項,即將一個大問題分解為n個原子問題(不可再分割),將這n個小問題解決後再逐漸合併,一般使用的是遞迴法。歸併排序是一種交穩定的排序演算法,時間複雜度固定式nlogn,但在實際操作中,其時間複雜度將會遠遠大於該值,因為在程式碼執行過程中不停的申請臨時記憶體和釋放記憶體,
遞迴實現二路歸併排序
#include<iostream> #include<vector> using namespace std; void merge(int arr[],int min,int m,int max){ int *tem=new int [max-min+1]; int k=0,i=min,j=m+1; while(i<=m&&j<=max){ if(arr[i]>arr[j]) tem[k++]=arr[j++]; else tem[k++]=arr[i++]; } while(i<=m)tem[k++]=arr[i++]; while(j<=max)tem[k++]=arr[j++]; //for(int l=0;l<=max-min;l++) //arr[l]=tem[l];//此處傳遞值是錯誤的,因為在一次迴圈中完成的是min到max的排序, //只要把該區間的數值傳遞即可 for(int l=min,p=0;l<=max;p++,l++) arr[l]=tem[p]; for(int ll=0;ll<10;ll++)//改程式碼可以清晰的看見排序過程,每次執行該函式的時候, //就是對min到max的排序,而且在排序結束之後改變了原arr陣列的值 cout<<arr[ll]; cout<<endl<<"-----------------"<<endl; } void Msort(int arr[],int min,int max){ if(min>=max) return; else{ Msort(arr,min,(min+max)/2); Msort(arr,(max+min)/2+1,max); merge(arr,min,(min+max)/2,max); } } int main(){ int arr[]={0,7,2,5,1,3,4,6,9,8}; Msort(arr,0,9); for(int i=0;i<10;i++) cout<<arr[i]; return 0; }
分析:如果對Merge的每個遞迴呼叫均區域性宣告一個臨時陣列,那麼在任意時刻就可能有logn個數組處在活動期,對記憶體是一個極大的消耗。另外在分配和收回上也會消耗很多時間。
時間複雜度的推算很複雜,涉及到疊縮求和,我認為在Msort函式中呼叫了logn次merge函式,在merge函式的排序的時間複雜度是N所以整個的時間複雜度是nlogn
另外二路歸併排序的迭代做法有效的防止了棧溢位,但是程式碼不夠簡潔,等我摸清楚後再更新
迭代實現二路遞迴排序
#include<iostream> #include<algorithm> using namespace std; void merge(int arr[],int min,int m,int max){ int *tem=new int [max-min+1]; int k=0,i=min,j=m+1; while(i<=m&&j<=max){ if(arr[i]>arr[j]) tem[k++]=arr[j++]; else tem[k++]=arr[i++]; } while(i<=m)tem[k++]=arr[i++]; while(j<=max)tem[k++]=arr[j++]; for(int l=min,p=0;l<=max;p++,l++) arr[l]=tem[p]; for(int ll=0;ll<10;ll++) cout<<arr[ll]; cout<<endl<<"-----------------"<<endl; } void Msort(int arr[],int n){ for(int step=2;step/2<=n;step*=2){//step表示步長,至於為什麼是2的次冪, //我想應該是對應logn, for(int i=0;i<=n;i+=step){ merge(arr,i,i+step/2-1,min(n-1,i+step-1)); } } } int main(){ int arr[]={9,8,7,6,5,4,3,2,1,0}; Msort(arr,10); for(int i=0;i<10;i++) cout<<arr[i]; return 0; }
分析:其實遞迴和非遞迴的merge函式基本沒什麼變化,主要思想就是怎麼將目標序列拆分,並按傳入merge函式,merge(arr,i,i+step/2-1,min(n-1,i+step-1));中的i+step/2-1表示傳入區間的中點,注意,該中點並非(min+max)/2,比如在區間為0 1 2 3 4 5 6 7 8 9 中,當步長為8時,前後區間的個數分別為8和2.
本來想使用vector陣列,這樣省去了動態申請陣列的過程,無奈道行太淺,怎麼都除錯不出來。稍後再試試。