一、歸並
假設現在的列表分兩段有序,如何將其合成為一個有序列表。這種操作稱為一次歸並。
1、歸並過程圖示
當一個列表兩段有序合並為一個有序列表的一次歸並的過程如下:
將列表分為兩段,兩個箭頭分別指向每段的第一個:

比較兩段中最小的數2和1,將最小的那個值,箭頭后移:

接着比較兩段中最小的數,將2取出,箭頭后移,以此類推:

2、歸並代碼實現
def merge(li, low, mid, high):
"""
歸並過程
:param li:列表
:param low:第一段第一個元素
:param mid:第一段最后一個元素
:param high:第二段最后一個元素
:return:
"""
i = low
j = mid + 1 # 第二段第一個元素
ltmp = [] # 新列表
while i <= mid and j<= high: # 只要左右兩邊都有數
if li[i] < li[j]:
ltmp.append(li[i])
i += 1
else:
ltmp.append(li[j])
j += 1
# while執行完,肯定會有一部分沒數了
while i<= mid : # 如果是第一部分仍有數
ltmp.append(li[i])
i += 1
while j <= high: # 如果是第二部分仍有數
ltmp.append(li[j])
j += 1
# 將ltmp的值寫回到li
li[low:high+1] = ltmp # 切片往回寫
li = [2, 4, 5, 7, 1, 3, 6, 8]
merge(li, 0, 3, 7)
print(li)
"""
[1, 2, 3, 4, 5, 6, 7, 8]
"""
二、歸並排序——使用歸並
歸並排序(MERGE-SORT)是利用歸並的思想實現的排序方法,該算法采用經典的分治(divide-and-conquer)策略(分治法將問題分(divide)成一些小的問題然后遞歸求解,而治(conquer)的階段則將分的階段得到的各答案"修補"在一起,即分而治之)。
1、歸並排序圖示

分解:將列表越分越小,直至分成一個元素。
終止條件:一個元素是有序的。
合並:將兩個有序列表歸並,列表越來越大。
2、歸並排序代碼實現
def merge(li, low, mid, high):
"""
歸並過程
:param li:列表
:param low:第一段第一個元素
:param mid:第一段最后一個元素
:param high:第二段最后一個元素
:return:
"""
i = low
j = mid + 1 # 第二段第一個元素
ltmp = [] # 新列表
while i <= mid and j<= high: # 只要左右兩邊都有數
if li[i] < li[j]:
ltmp.append(li[i])
i += 1
else:
ltmp.append(li[j])
j += 1
# while執行完,肯定會有一部分沒數了
while i<= mid : # 如果是第一部分仍有數
ltmp.append(li[i])
i += 1
while j <= high: # 如果是第二部分仍有數
ltmp.append(li[j])
j += 1
# 將ltmp的值寫回到li
li[low:high+1] = ltmp # 切片往回寫
def _merge_sort(li, low, high): # 遞歸函數
"""歸並排序"""
if low < high: # 翟少有兩個元素,遞歸
mid = (low + high) // 2
_merge_sort(li, low, mid) # 把左邊排好序
_merge_sort(li, mid+1, high) # 把右邊排好序
merge(li, low, mid, high)
print(li[low: high+1])
def merge_sort(li):
return _merge_sort(li, 0, len(li)-1)
li = list(range(10))
import random
random.shuffle(li)
print(li)
merge_sort(li)
print(li)
"""
[6, 2, 8, 3, 1, 9, 7, 5, 4, 0]
[2, 6]
[2, 6, 8]
[1, 3]
[1, 2, 3, 6, 8]
[7, 9]
[5, 7, 9]
[0, 4]
[0, 4, 5, 7, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
"""
3、歸並和歸並排序時間、空間復雜度
每一層的時間復雜度是O(n),層數是logn。因此總的時間復雜度是O(nlogn)。
由於merge函數創建了一個ltmp的臨時空間,到最大的時候長度是n,空間復雜度是O(n)。不再是原地排序。
