算法——歸併和歸併排序

1、歸併

  假設如今的列表分兩段有序,如何將其合成爲一個有序列表。這種操做稱爲一次歸併。python

一、歸併過程圖示

  當一個列表兩段有序合併爲一個有序列表的一次歸併的過程以下:算法

  將列表分爲兩段,兩個箭頭分別指向每段的第一個:app

  

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

  

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

  

 

二、歸併代碼實現

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]
"""

2、歸併排序——使用歸併

  歸併排序(MERGE-SORT)是利用歸併的思想實現的排序方法,該算法採用經典的分治(divide-and-conquer)策略(分治法將問題(divide)成一些小的問題而後遞歸求解,而治(conquer)的階段則將分的階段獲得的各答案"修補"在一塊兒,即分而治之)。
函數

一、歸併排序圖示

  

  分解:將列表越分越小,直至分紅一個元素。spa

  終止條件:一個元素是有序的。blog

  合併:將兩個有序列表歸併,列表愈來愈大。排序

二、歸併排序代碼實現

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]
"""

三、歸併和歸併排序時間、空間複雜度  

  每一層的時間複雜度是O(n),層數是logn。所以總的時間複雜度是O(nlogn)遞歸

  因爲merge函數建立了一個ltmp的臨時空間,到最大的時候長度是n,空間複雜度是O(n)。再也不是原地排序。

相關文章
相關標籤/搜索