1. 程式人生 > >演算法 歸併排序的複雜度分析(含圖解流程和Master公式)

演算法 歸併排序的複雜度分析(含圖解流程和Master公式)

圖解流程

整體流程如下:
這裡寫圖片描述

細節流程:
第一步:
這裡寫圖片描述

第二步:
這裡寫圖片描述

第三步:
這裡寫圖片描述

第四步:
這裡寫圖片描述

第五步:

這裡寫圖片描述

第六步:
這裡寫圖片描述

第七步:
這裡寫圖片描述

第八步:

這裡寫圖片描述

第九步:
這裡寫圖片描述

第十步:
這裡寫圖片描述

程式碼

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),穩定性排序