原理就是不斷將array切割成左右兩塊,左右兩塊利用遞迴特性繼續切割,直到切到最小單位時,才會開始合併,合併時才真正比較大小做排序,也是Divide and Conquer的運用
流程大概如下:
將array分成左半部跟右半部
左半和右半重複做1的動作(遞迴, 不斷切半)
合併左半右半(不斷合併)
pseudo code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* 切割 */ MergeSort(A[1..n]) if n = 1: return A m ← n/2 // 左右兩個array Array left[1..m] Array right[1..n-m] // 將原array的值assign到左右兩個array for i from 1 to n: left[i] ← A[i] for i from 1 to n-m: right[i] ← A[m+i] // 遞迴 MergeSort(left) MergeSort(right) Merge(A, left, right)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/* 合併, 開始比大小 */ Merge(A[1..n], left[1..n/2], right[1..(n-n/2)]) i ← 1 j ← 1 k ← 1 // 比較小的就先塞到array A while i < leftSize and j < rightSize: if left[i] <= right[j]: A[k++] ← left[i++] else: A[k++] ← right[j++] // 如果有剩餘的值就全部塞入array A(因為左右兩個array的大小可能不同) while i < leftSize: A[k++] ← left[i++] while j < rightSize: A[k++] ← right[j++]
複雜度比較
時間複雜度
Sequence
Complexity
Random
$O(NlogN)$
Nearly Sorted
$O(NlogN)$
Reversed
$O(NlogN)$
Few Unique
$O(NlogN)$
Merge sort 的時間複雜度在所有情況下都是 $O(NlogN)$, 獨立於資料的組成
空間複雜度
因為需要用到額外的 array 來儲存分割的資料作排序,用到 $O(n)$ space 如果用 linked list,則是 $O(logN)$ space