1. 程式人生 > >高級排序算法之歸並排序

高級排序算法之歸並排序

思想 復雜度 align 策略 十年 template logs 機器 想是

在自己摸爬滾打前行或是後退的時候,總會出現很多的驚喜或意外




樓主大三狗,前些天異想天開想面試青少年編程老師一職


沒想到對面坐的是科大訊飛十年辭職創業的高級攻城獅。。。


很尬,未果。我說了近況,並沒有潛心研究算法雲雲,一直在入門機器學習,深度學習


他說本科生在沒有能力的情況下不要研究這些……最好學學算法,以後出來找工作肯定是不成問題的。。


前言背景有點長,下面正式開始


歸並排序是一種高效率的算法,時間復雜度只有O(nlogn)
它的核心思想是分治策略
如下圖,分是將其二分至不可再分
技術分享圖片
分完需要再合,合的方法是如下
技術分享圖片
倆倆互相比較大小,做好排序,這裏的已經合並的還剩下最後一步。


到了思想關鍵的地方了,如何給這些進行排序呢?

需要創建一個數組,來保存原數組信息,在拿拷貝的數組進行對原數組進行修改,即排序
需要建立三個遊標,如下:
<ignore_js_op>技術分享圖片


下面一行為拷貝數組,將兩端進行比較,設左端為起始為l,末端為mid;右端起始即為mid+1,末端為r
設遍歷遊標為i,j
取第一個元素比較做範例,若arr[l] < arr[mid+1] 則將原數組a[k] = arr[l]值即可


所以大致分類如下:
1.如果 i > mid,則說明左端遍歷已結束;
2.如果j > r,則說明右端遍歷已結束;
3.如果上述兩者都不滿足,則說明兩端遍歷都沒有結束,則比較arr與arr[j]的關系即可

3.1. 若arr > arr[j] ,則原數組a[k] = arr[j] ,此時 j ++ ,k++,j,k自增,遊標向右移; 3.2 .若arr < arr[j] ,則原數組a[k] = arr , 此時 i ++ ,k ++,i,k自增,遊標向右移。

不明白如何分治,如下博客:https://www.cnblogs.com/wyongbo/p/Devide.html
貼出代碼,困於遞歸很久,畢竟接觸的少
如果有對遞歸不熟悉的可以在函數裏多使用printf函數來進行輸出,探測函數的走向
//歸並排序算法
template<typename T>
void __Merge(T arr[], int l, int mid, int r)
{
	printf("\n排序函數入口 l = %d, mid = %d, r = %d \n", l, mid, r);
	T* aux = new T[r - l + 1];		//創建數組指針,新版可以直接使用變量創建,如下一行代碼
	//T aux[r - l + 1];				//創建一個數組
	for (int i = l; i <= r; i++)	//拷貝數組
	{
		aux[i - l] = arr[i];
		printf("拷貝數組a[%d] = arr[%d] = %d \n", i - l, i, arr[i]);
	}

	int i = l, j = mid + 1;			//將數組分成兩部分進行比較
	for (int k = l; k <= r; k++)
	{
		//判斷位置合法性,左端已遍歷結束
		if (i > mid)
		{
			arr[k] = aux[j - l];
			j++;
		}//判斷位置合法性,右端遍歷已結束
		else if (j > r)
		{
			arr[k] = aux[i - l];
			i++;
		}//合法情況,進行比較
		else if (aux[i - l] < aux[j - l])
		{
			arr[k] = aux[i - l];
			i++;
		}
		else
		{
			arr[k] = aux[j - l];
			j++;
		}
	}
	delete []aux;
}

template<typename T>
void __MergeSort(T arr[], int l, int r)
{
	if (l >= r)
		return;
	int mid = (l + r) / 2;
	__MergeSort(arr, l, mid);
	__MergeSort(arr, mid + 1, r);
	__Merge(arr, l, mid, r);
}

template<typename T>
void MergeSort(T arr[], int n)
{
	__MergeSort(arr, 0, n - 1);
}

  

高級排序算法之歸並排序