演算法 歸併排序的複雜度分析(含圖解流程和Master公式)
阿新 • • 發佈:2019-01-04
圖解流程
整體流程如下:
細節流程:
第一步:
第二步:
第三步:
第四步:
第五步:
第六步:
第七步:
第八步:
第九步:
第十步:
程式碼
public static void mergeSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
mergeSort(arr, 0, arr.length - 1);
}
public static void mergeSort(int[] arr, int L, int R) {
if (L == R) {
return;
}
int mid = (L + R) / 2;
//將陣列左側全部排成有序
mergeSort(arr, L, mid);//T(N/2)
//將陣列右側全部排成有序
mergeSort(arr, mid + 1, R);//T(N/2)
merge(arr, L, mid, R);//O(N):因為N個數的話,需要依次掃過去
}
private static void merge(int[] arr, int L, int mid, int R) {
//開闢一個臨時陣列,用來存放歸併過程中的排好序的元素
int[] help = new int[R - L + 1];
//臨時陣列的索引
int i = 0;
int p1 = L;
int p2 = mid + 1;
while (p1 <= mid && p2 <= R) {
if (arr[p1] <= arr[p2]) {
help[i] = arr[p1];
i++;
p1++;
} else {
help[i] = arr[p2];
i++;
p2++;
}
}
while (p1 <= mid) {
help[i] = arr[p1];
i++;
p1++;
}
//上面的while迴圈和下面的while迴圈只會執行一個
while (p2 <= R) {
help[i] = arr[p2];
i++;
p2++;
}
for (int j = 0; j < help.length; j++) {
// 這裡要用arr[L+j]接受,因為每次進來歸併排序的陣列起始索引是L,長度是help的長度
arr[L + j] = help[j];
}
}
Master公式
T(N) = a*T(N/b) + O(N^d)
1) 如果log(b,a) > d –> 複雜度為O(N^log(b,a))
2) 如果log(b,a) = d –> 複雜度為O(N^d * logN)
3) 如果log(b,a) < d –> 複雜度為O(N^d)
時間複雜度和額外空間複雜度
時間複雜度:
1、我們設mergeSort的時間複雜度為T(N)
2、從巨集觀上看,他分別呼叫了兩次自己的函式mergeSort和一次merge,那麼T(N)等於兩次mergeSort的時間複雜度和一次merge的時間複雜度
3、呼叫自己的函式的時候,函式個數為N/2,則T(N)=2*T(N/2)+一次merge的時間複雜度
4、根據上面的流程分析merge總共掃描了N個數,執行了N次,所以時間複雜度為O(N)
5、所以T(N)=2*(N/2)+O(N)
6、根據Master公式,此時a=2,b=2,d=1,滿足log(b,a) = d
7、所以歸併排序時間複雜度為:O(N^d * logN)=O(N* logN)
額外空間複雜度:
因為我們每次執行merge的時候,都需要建立一個help陣列,而這個help最大是N個數,需要N個空間,所以額外空間複雜度為O(N),穩定性排序