歸併排序的簡單實現(c++ 版本)
阿新 • • 發佈:2019-02-13
歸併排序
歸併排序是建立在歸併操作上的一種有效的排序演算法,該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。
將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,也稱為二路歸併。
實現
首先先來實現將兩個有序的子序列合併成一個有序的序列。
先將歸併的序列分成兩個,左邊的B和右邊的C,為了節省空間,我們將左邊的部分另申請空間儲存,即 B = new T,而右邊的部分並不申請記憶體,直接將地址賦值給 C,
合併的時候就像是有序連結串列的合併一樣,每次比較 B 和 C中的元素,並將較小的儲存到A中。
注意到C中本來就儲存在A中,因而如果C中元素沒有用完,而B中的元素已經用完,那麼就可以直接跳出迴圈,因為C已然在A中對應的位置(字尾)。
最後刪除B即可,這時,最初的 elem陣列中 lo 到 hi 之間的元素就已經有序了。
複雜度:每次迴圈 都有C[k++], B[j++] ,最壞情況也只要O(n)。
合併有序向量
template <typename T> void merge(int lo,int mi,int hi,T *elem){ T *A = elem + lo; int lb = mi-lo; T *B = new T[lb]; //左邊 for(int i=0;i<lb;B[i] = A[i++]) ; //複製到左邊 B int lc = hi - mi; T *C = elem + mi; for(int i=0,j=0,k=0; j<lb; ){ if((k < lc) && (C[k] <B[j])) A[i++] = C[k++]; if(lc <= k || (B[j] <= C[k])) A[i++] = B[j++]; } delete []B; }
歸併排序的主體部分(分而治之)
template <typename T> void mergeSort(int lo,int hi,T *elem){
if(hi - lo < 2) return ; //單元素區間自然有序
int mi = (lo + hi) >> 1;
mergeSort(lo,mi ,elem); //遞迴的歸併排序左邊
mergeSort(mi,hi,elem); //遞迴的歸併排序右邊
merge(lo, mi,hi,elem); //合併
}
最終的複雜度
可以看出 每次遞迴只是將問題分成兩個 原來規模一半的問題,而每個問題只要進行上述 O(n)效率的merge,
所以時間複雜度 T(n) = 2 * T(n/2) + O( n ), 也就是 O(n * log n).
測試的主函式
int main()
{
int elem[110];
srand((unsigned)time(NULL));
for(int i = 0; i < 20;i++ )
elem[i] = rand();
cout<<"---------------before sort------------"<<endl<<endl;
for(int i=0;i<20;i++)
printf("%d ",elem[i]);
cout<<endl<<endl;
cout<<"---------------after sort------------"<<endl<<endl;
mergeSort(0,20,elem);
for(int i=0;i<20;i++)
printf("%d ",elem[i]);
cout<<endl;
return 0;
}