常用算法排序(04)—— 歸併排序

一、 歸併排序的基本思想

歸併排序是利用先遞歸進行分解,將一個規模爲 nn 的問題分解成兩個規模爲 n/2n/2 的問題,再不斷的繼續進行遞歸分解成最終規模爲11的問題。然後再逐漸的從小規模結果進行合併,最終得到完整的結果。也即分而治之的思想。
其圖解如下:原圖地址
在這裏插入圖片描述


二、算法分析

歸併排序使用了空間換時間的方式,用一個輔助數組來存儲每次排序後的結果,然後再將其複製到原數組對應的位置上,會將原數組中對應位置上 的值覆蓋掉。
1、如數組 [4,3,2,1] 的遞歸子問題爲 [4,3] 和 [2,1] 其中先將 [4,3] 的排序結果放在輔助數組 temp 中(temp的大小爲原數組 arr 的大小)。然後再將在 temp數組中排好序的結果複製到 arr 數組中的對應位置上,如下圖所示。遞歸這個過程就是歸併排序。
在這裏插入圖片描述
2、第一次遞歸後的排序結果如下

在這裏插入圖片描述

三、代碼

#include<iostream>
#include<string>
using namespace std;

void Merge(int *arr, int *temp, int left, int mid,int right)
{
	int i = left;  //左邊遞歸數組的指針
	int j = mid + 1; //右邊遞歸數組的指針
	int index = 0;

	while (i <= mid && j<=right)
	{
		if (arr[i] < arr[j])
		{
			temp[index++] = arr[i++];
		}
		else
		{
			temp[index++] = arr[j++];			
		}
	}
	while (i <= mid)
	{
		temp[index++] = arr[i++];
	}
	while (j <= right)
	{
		temp[index++] = arr[j++];
	}

	index = 0;
	while (left <= right)
		arr[left++] = temp[index++];

}

void MergeSort(int *arr, int *temp, int left,int right)
{
	
	if (left < right)
	{
		int mid = left + (right - left) / 2;
		MergeSort(arr, temp, left, mid);   //左邊歸併排序,使得左子序列有序
		MergeSort(arr, temp, mid + 1, right); //右邊歸併排序,使得右子序列有序
		Merge(arr, temp, left, mid, right);   //將兩個有序子數組合並排序
	}
}

int main()
{
	int arr[] = { 4,3,2,1 };
	int len = sizeof(arr) / sizeof(arr[0]);
	//創建一個長度等於原數組長度的輔助數組,避免遞歸中頻繁開闢空間
	int *temp = new int[len];

	MergeSort(arr,temp, 0, len-1);
	delete[] temp;

	for (int i = 0; i < len; ++i)
		cout << arr[i] << " ";

	cout << endl;

	system("pause");
	return 0;
}

運行結果如下:
在這裏插入圖片描述

四、複雜度分析

  • 空間複雜度爲 O(n)O(n)
  • 時間複雜度爲 O(nlogn)O(nlogn)

參考資料:
圖解排序算法(四)之歸併排序
排序算法總結之歸併排序

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