歸併排序
歸併排序(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,比較結束。
- 最後剩下的指標指向的資料(包含該指標指向資料後面所有的資料)直接新增到新列表中即可。
- 下圖中的倒數第三行表示為第一次合併後的資料。其中一組資料為 4 8 , 5 7。該兩組資料合併方式為:每一小組資料中指定一個指標,指標指向每小組資料的第一個元素,通過指標的偏移指定資料進行有序排列。排列情況如下:
- 如何合併?
- 直到所有子序列的長度都為1,也就是不可以再二分截止。這時候再兩兩合併成一個有序序列即可。
原理圖示
穩定性
相同元素在順序重排之後,其前後順序不會發生變化,故歸併排序是一種穩定的排序演算法
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]