排序演算法之 '歸併排序'

嗨,阿良發表於2020-07-19

歸併排序

歸併排序(Merge Sort)是建立在歸併操作上的一種有效,穩定的排序演算法,該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱為二路歸併。

歸併排序採用分而治之的原理:

  • 將一個序列從中間位置分成兩個序列;

  • 再將這兩個子序列按照第一步繼續二分下去;

    • 直到所有子序列的長度都為1,也就是不可以再二分截止。這時候再兩兩合併成一個有序序列即可。
      • 如何合併?
        • 下圖中的倒數第三行表示為第一次合併後的資料。其中一組資料為 4 8 , 5 7。該兩組資料合併方式為:每一小組資料中指定一個指標,指標指向每小組資料的第一個元素,通過指標的偏移指定資料進行有序排列。排列情況如下:
          • left_pointer指向4,right_pointer指向5,left_pointer和right_pointer指向的元素4和5進行比較,較小的資料歸併到一個新的列表中。經過比較left_pointer指向的4會被新增到新的列表中,則left_pointer向後偏移一位,指向了8,right_pointer不變。
          • left_pointer和right_pointer指向的元素8,5繼續比較,則right_pointer指向的5較小,新增到新列表中,right_pointer向後偏移一位,指向了7。
          • left_pointer和right_pointer指向的元素8,7繼續比較,7新增到新列表中,right_pointer偏移指向NULL,比較結束。
          • 最後剩下的指標指向的資料(包含該指標指向資料後面所有的資料)直接新增到新列表中即可。

原理圖示

img

穩定性

相同元素在順序重排之後,其前後順序不會發生變化,故歸併排序是一種穩定的排序演算法

Python實現

def merge_sort(alist):
    n = len(alist)
    # 結束遞迴的條件
    if n <= 1:
        return alist
    # 中間索引
    mid = n // 2

    left_li = merge_sort(alist[:mid])
    right_li = merge_sort(alist[mid:])

    # 指向左右表中第一個元素的指標
    left_pointer, right_pointer = 0, 0

    # 合併資料對應的列表:該表中儲存的為排序後的資料
    result = []

    while left_pointer < len(left_li) and right_pointer < len(right_li):
        # 比較最小集合中的元素,將最小元素新增到result列表中
        if left_li[left_pointer] < right_li[right_pointer]:
            result.append(left_li[left_pointer])
            left_pointer += 1
        else:
            result.append(right_li[right_pointer])
            right_pointer += 1

    # 當左右表的某一個表的指標偏移到末尾的時候,比較大小結束,將另一張表中的資料(有序)新增到result中
    result += left_li[left_pointer:]
    result += right_li[right_pointer:]

    return result


if __name__ == '__main__':
    alist = [8, 4, 5, 7, 1, 3, 6, 2]
    print(merge_sort(alist))

# [1, 2, 3, 4, 5, 6, 7, 8]

相關文章