歸併排序的基本思想

歸併排序是一種基於分治法(Divide and Conquer)的高效排序算法。它的核心思路可以概括爲三個步驟:分解(Divide)遞歸排序(Conquer)合併(Merge)

  • 分解:將待排序的數組從中間分成左右兩部分,直到每個子數組只包含一個元素(此時子數組本身就是有序的)。
  • 遞歸排序:對左右兩個子數組分別遞歸執行歸併排序,直到所有子數組都有序。
  • 合併:將兩個已排序的子數組合併成一個更大的有序數組,最終得到整個數組的排序結果。

簡單來說,歸併排序就是先把大問題拆分成小問題,解決小問題後再把結果合併起來。

分解過程詳解

假設我們有一個數組 [3, 1, 4, 2],歸併排序的分解過程如下:

  1. 第一次分解:數組長度爲4,中間位置是 4//2=2,所以分成左右兩部分:left = [3, 1]right = [4, 2]
  2. 遞歸分解左子數組 [3, 1]:中間位置是 2//2=1,分成 left_left = [3]left_right = [1](每個子數組長度爲1,無需再分解)。
  3. 遞歸分解右子數組 [4, 2]:中間位置是 2//2=1,分成 right_left = [4]right_right = [2](每個子數組長度爲1,無需再分解)。

遞歸排序與合併

當分解到子數組長度爲1時,子數組已經有序(單個元素本身就是有序的)。此時需要執行合併操作,將兩個有序子數組合併成一個更大的有序數組。

以分解後的子數組爲例:
- 左子數組合並:[3][1] 合併成 [1, 3]
- 右子數組合並:[4][2] 合併成 [2, 4]
- 最終合併:[1, 3][2, 4] 合併成 [1, 2, 3, 4]

Python代碼實現

下面是歸併排序的Python實現,分爲合併函數遞歸排序函數兩部分:

1. 合併函數 merge(left, right)

功能:合併兩個已排序的子數組,返回一個新的有序數組。

def merge(left, right):
    merged = []  # 存儲合併後的結果
    i = j = 0    # 兩個子數組的指針(索引)

    # 比較兩個子數組的元素,按順序加入merged
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            merged.append(left[i])
            i += 1
        else:
            merged.append(right[j])
            j += 1

    # 將剩餘未比較的元素直接加入(可能其中一個子數組已遍歷完)
    merged.extend(left[i:])  # 添加left中剩餘元素
    merged.extend(right[j:]) # 添加right中剩餘元素
    return merged

2. 遞歸排序函數 merge_sort(arr)

功能:遞歸分解數組,調用合併函數得到排序結果。

def merge_sort(arr):
    # 基本情況:數組長度爲1或0時,本身就是有序的
    if len(arr) <= 1:
        return arr

    # 分解數組:分成左右兩部分
    mid = len(arr) // 2
    left = merge_sort(arr[:mid])   # 遞歸排序左半部分
    right = merge_sort(arr[mid:])  # 遞歸排序右半部分

    # 合併兩個已排序的子數組
    return merge(left, right)

測試代碼

if __name__ == "__main__":
    test_array = [3, 1, 4, 2, 5]
    sorted_array = merge_sort(test_array)
    print("原始數組:", test_array)
    print("排序後數組:", sorted_array)

輸出結果

原始數組: [3, 1, 4, 2, 5]
排序後數組: [1, 2, 3, 4, 5]

歸併排序的特點

  • 時間複雜度:無論輸入數組如何,歸併排序的時間複雜度始終爲 O(n log n)(分解和合並的總操作次數爲O(n log n))。
  • 空間複雜度:需要額外的數組存儲合併結果,空間複雜度爲 O(n)
  • 穩定性:歸併排序是穩定的排序算法(相等元素的相對順序保持不變)。

歸併排序的核心是“分而治之”和“合併有序數組”,通過遞歸分解和合並,最終實現整個數組的排序。雖然代碼看起來比冒泡排序等簡單排序算法複雜,但理解其思路後,會發現它非常直觀且高效。

小夜