1. 程式人生 > >Python3&資料結構之合併(歸併)排序

Python3&資料結構之合併(歸併)排序

合併(歸併)排序和快速排序一樣也採用了分而治之(divide and conquer,D&C)的思想

不過對比快速排序,mergesort沒有pivot(中心點)

分的部分:

  • 它是把一個無序陣列按照陣列大小的中心數分為兩部分
    if len(n) < 2:     #分的階段,即divide
        return n
    mid = len(n) // 2
  • 然後採用遞迴的思想把分好的兩部分,再分成兩部分,這樣總共就有4部分了,依次類推。
    left = mergesort(n[:mid])
    right = mergesort(n[mid:])

治的部分:

  • 建立一個空的列表
    merged = []
  • 把分好的兩部分按照索引比較,如果是從小到大排序,那麼左右兩部分哪個數值小,就把哪個放到新建立的列表中
  • 然後對之對應的部分(左部或者右部)的索引值+1,依次類推,直到一方的數值全部比較完,即索引值=len(left/right)
    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:])
    merged.extend(right[j:])

圖解思想請參考:https://www.cnblogs.com/chengxiao/p/6194356.html

完整的mergesort程式碼以及測試

#mergesort
def merge(left,right):  #治的階段,即conquer
    merged = []
    i,j = 0,0
    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:])
    merged.extend(right[j:])
    return merged

def mergesort(n):
    if len(n) < 2:     #分的階段,即divide
        return n
    mid = len(n) // 2
    left = mergesort(n[:mid])
    right = mergesort(n[mid:])
    return merge(left,right)

if __name__ == '__main__':
    test = [49, 38, 65, 97, 76, 13, 27, 49]
    print(mergesort(test))

那麼現在很容易就看出合併排序和快速排序的差別了,即合併排序需要先分再治,即O(2*logn)

再乘上每層遞迴上的操作,時間複雜度O(2nlogn),因為在算時間複雜度的時候要忽略前面的係數2

所以雖然合併排序的時間複雜度和快速排序的平均時間複雜度一樣為O(nlogn)

但快速排序並沒有前面的係數2,所以在一般情況下,快速排序要比合並排序略快,有興趣的朋友可以加個時間做比較。

PS:如果時間允許的情況下,筆者會在寫完常用的幾種排序演算法之後,做個時間比較。