1. 程式人生 > >歸併排序的簡單實現(c++ 版本)

歸併排序的簡單實現(c++ 版本)

歸併排序

歸併排序是建立在歸併操作上的一種有效的排序演算法,該演算法是採用分治法(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; 
}

執行結果