七種排序--------歸併排序(Merging Sort)

歸併排序就是利用歸併的思想實現的排序方法。他的原理是假設初始序列含有n個記錄,則可以看成是n個有序的子序列,每個子序列的長度爲1,然後兩兩歸併,得到[n/2] (整數)個長度爲2或1的有序子序列;再兩兩歸併,......,如此重複,直至得到一個長度爲n的有序序列爲止,這種排序方法稱爲2路歸併排序。

先來看代碼:

void MergeSort(Sqlist *L)
{
	MSort(L->r,L->r,1,L->length);
}

只是調用了一個函數,封裝了一下,假設現在要對數組{50,10,90,30,70,40,80,60,20}進行排序,L.length = 9,則來看看MSort()函數的實現:

void MSort(int SR[],int TR1[],int s,int t)
{
	int m;
	int TR2[MAXSIZE + 1];
	if(s == t)
		TR1[s] = SR[s];
	else
	{
		m = (s + t)/2;
		MSort(SR,TR2,s,m);
		MSort(SR,TR2,m+1,t);
		Merge(TR2,TR1,s,m,t);
	}
}

1.MSort()bei'被調用時,SR與TR1都是{50,10,90,30,70,40,80,60,20},s = 1,t = 9。

2.第5行 顯然s不等於t,執行第8~13行語句塊。

3.第9行,m = (1+9)/2 = 5,m就是序列的正中間的下標。

4.此時第10行,調用MSort(SR,TR2,1,5)的目標就是將數組SR中的第1~5的關鍵字歸併到有序的TR2(調用前TR2爲空數組),第11行調用MSort(SR,TR2,6,9)的目標就是將數組SR中的第6~9的關鍵字歸併到有序的TR2.也就是說,在調用這兩句代碼之前,代碼已經準備將數組分成了兩組了。

5.第12行就是分別將數組變得有序。

6.最後遞歸進去之後總的來說就是按照下圖進行遞歸返回(圖來自大話數據結構):

            

再來看一下Merge函數的代碼:

/*將有序的SR[i..m]和SR[m+1..n]歸併爲有序的TR[i..n]*/
void Merge(int SR[],int TR[],int i,int m,int n)
{
	int j,k,l;
	for(j = m +1,k = i;i <= m && j <= n;k++)    //將SR中記錄由小到大歸併到TR
	{
		if(SR[i] < SR[j])
			TR[k] = SR[i++];
		else
			TR[k] = SR[j++];
	}
	
	if(i <= m)
	{
		for(l = 0;l <= m - i;l++)
			TR[k + l] = SR[i + l];              //將剩餘的SR[i..m]複製到TR
	}
	
	if(j <= n)
	{
		for(l = 0;l <= n - j;l++)
			TR[k + l] = SR[j + l];              //將剩餘的SR[j..n]複製到TR
	}
}

複雜度分析:

時間複雜度爲O(nlogn);

空間複雜度爲O(n + logn);

 

非遞歸實現歸併排序

直接看代碼:

/*對順序表L作歸併非遞歸排序*/
void MergeSort2(Sqlist *L)
{
	int *TR = (int *)malloc(L->length*sizeof(int));  //申請額外空間
	int k = 1;
	while(k < L->length)
	{
		MergePass(L->r,TR,k,L->length);
		k = 2*k;                                    //子序列長度加倍
		MergePass(TR,L->r,k,L->length);
		k = 2*k;                                    //子序列長度加倍
	}
}

MergePass()函數的實現:

/*將SR[]中相鄰長度爲s的子序列兩兩歸併到TR[]中*/
void MergePass(int SR[],int TR[],int s,int n)
{
	int i = 1;
	int j;
	while(i <= n - 2*s + 1)
	{
		Merge(SR,TR,i,i+s-1,i+2*s-1);                  //兩兩歸併
		i = i + 2*s;
	}
	
	if(i < n-s+1)                                      //歸併最後兩個序列
		Merge(SR,TR,i,i+s-1,n);
	else                                               //若最後只剩下單個子序列
		for(j = i;j <= n;j++)
			TR[j] = SR[j];
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章