03歸併排序

1.基本思想

歸併排序(Merge Sort)的核心是分治,將一個複雜問題分解成多個相同或相似的子問題,然後把子問題分解成更小的問題,知道子問題可以簡單地求解,最原始問題的解就是子問題解的合併。

一開始先將數組從中間分成兩個子數組,一直遞歸把子數組劃分成更小的子數組,直到子數組裏只包含一個元素,這時纔開始排序。排序的方法就是按照大小的順序合併兩個元素,接着依次按照遞歸返回的順序,不斷合併排好序的子數組,直到最後把整個數組的順序排好。

例題:利用歸併排序算法對數組 [2, 1, 7, 9, 5, 8] 進行排序。
歸併排序動畫

2.C++代碼實現

編譯環境:win10系統,vs2013

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

//合併函數
void merge(vector<int> &arr, int l, int m, int r) {
	vector<int> arr_copy(arr);

	//定義一個變量k,表示從什麼位置開始改變原來的數組
	//i表示左邊部分的起始位置的下標,j表示右邊部分的起始位置的下標
	int k = l, i = l, j = m + 1;
	while (k <= r) {
		if (i > m) {
			arr[k++] = arr_copy[j++];
		}
		else if (j > r) {
			arr[k++] = arr_copy[i++];
		}
		else if (arr_copy[i] > arr_copy[j]) {
			arr[k++] = arr_copy[j++];
		}
		else {
			arr[k++] = arr_copy[i++];
		}
	}
}
//歸併排序
void mergeSort(vector<int> &arr, int l, int r) {
	//判斷是否只剩下一個元素
	if (l >= r) return;

	//將數組從中間分成兩部分呢
	int m = l + (r - l) / 2;
	mergeSort(arr, l, m);
	mergeSort(arr, m + 1, r);

	//將排好序的左右兩半合併
	merge(arr, l, m, r);
}

//打印vector
void printVector(vector<int> &v) {
	for (auto &i : v)
		cout << i << " ";
	cout << endl;
}
int main()
{
	vector<int> vec = { 2, 1, 7, 9, 5, 8 };
	cout << "給定數組爲:";
	printVector(vec);

	mergeSort(vec, 0, vec.size() - 1);
	cout << "歸併排序後:";
	printVector(vec);
	system("pause");
	return 0;
}

merge函數中,While 語句中,while的結束條件爲k<=l,一共可能會出現四種情況。

  • 左半邊的數都處理完畢,只剩下右半邊的數,只需要將右半邊的數逐個拷貝過去。
  • 右半邊的數都處理完畢,只剩下左半邊的數,只需要將左半邊的數逐個拷貝過去就好。
  • 右邊的數小於左邊的數,將右邊的數拷貝到合適的位置,j 指針往前移動一位。
  • 左邊的數小於右邊的數,將左邊的數拷貝到合適的位置,i 指針往前移動一位。

輸出

給定數組爲:2 1 7 9 5 8
歸併排序後:1 2 5 7 8 9
請按任意鍵繼續. . .

3.算法分析

空間複雜度:O(n)
由於合併n個元素需要額外分配一個大小爲n的數組,合併完成後釋放,所以算法的空間複雜度爲O(n)。歸併排序也是穩定的排序算法
時間複雜度:O(nlogn)
歸併排序是一種遞歸算法,時間複雜度可以表示爲以下遞歸關係:T(n) = 2×T(n/2) + O(n)
公式解釋:
舉例:數組的元素個數是 n,時間複雜度是T(n)的函數。
解法:把這個規模爲n的問題分解爲兩個規模爲n/2的子問題,每個子問題的時間複雜度爲T(n/2),則兩個子問題的複雜度之和爲2xT(n/2)。當兩個子數組都排好序了,需要將它們合併,一共有n個元素,需要進行n-1次的比較,所以合併的複雜度爲O(n)。因此遞歸複雜度的公式爲:T(n) = 2×T(n/2) + O(n)

對於公式的求解,是將規模爲n的問題分解爲規模爲n/2的問題,一直分解爲規模爲1。如果n爲2,需要分1次,如果n爲4,需要分2次,以此類推,如果規模就爲n,則需要分logn次。而在每一次的合併中,所涉及到的元素就是數組中的所有元素,因此每次合併的複雜度都是O(n)。所有整體的複雜度爲O(nlogn)

4.參考博客

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