算法——歸並和歸並排序


一、歸並

  假設現在的列表分兩段有序,如何將其合成為一個有序列表。這種操作稱為一次歸並。

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)。不再是原地排序。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM