算法漫游指北(第十一篇):歸並排序算法描述、動圖演示、代碼實現、過程分析、復雜度


一、歸並排序

歸並排序是建立在歸並操作上的一種有效的排序算法。該算法是采用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合並,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合並成一個有序表,稱為2-路歸並。

  • 所謂“分”,指的是將一個亂序數列不斷進行二分,得到許多短的序列。

  • 所謂“治”,指的是將這些短序列進行兩兩合並,然后將合並的結果作為新的序列,再與其他序列進行合並,最終得到一個新的序列。

歸並排序算法描述

 

  • 把長度為n的輸入序列分成兩個長度為n/2的子序列;

  • 對這兩個子序列分別采用歸並排序;

  • 將兩個排序好的子序列合並成一個最終的排序序列。

 

歸並排序動圖演示

 

動畫演示圖2

 

 

歸並排序代碼實現

def merge_sort(alist):
    """歸並排序"""
    n = len(alist)
    #遞歸結束條件
    # 剩一個或沒有直接返回,不用排序
    if n <= 1:
        return alist
    # 拆分
    mid = n//2
​
    # left 采用歸並排序后形成的有序的新的列表
    left_li = merge_sort(alist[:mid])
​
    # right 采用歸並排序后形成的有序的新的列表
    right_li = merge_sort(alist[mid:])
​
    # 將兩個有序的子序列合並為一個新的整體
    # merge(left, right)
    left_pointer, right_pointer = 0, 0
    result = []
​
    while left_pointer < len(left_li) and right_pointer < len(right_li):
        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
​

  


歸並排序過程分析

示例 針對 arrli = [6,5,3,1,8,7,2,4]進行歸並排序

1、拆分數組

假設數組一共有 n 個元素,我們遞歸對數組進行折半拆分即n//2,直到每組只有一個元素為止。

 

2、合並數組

算法會從最小數組開始有序合並,這樣合並出來的數組一直是有序的,所以合並兩個有序數組是歸並算法的核心,這里用兩個簡單數組示例:

步驟1:新建一個空數組存放合並結果,用left_pointerright_pointer兩個輔助指針記錄兩個數組當前操作位置;

 

步驟2:從左到右逐一比較兩個小數組中的元素,較小的元素先放入新數組,指針移位,直到left_pointerright_pointer指針超出尾部;

 

步驟3:新建一個空數組存放合並結果,用lr兩個輔助指針記錄兩個數組當前操作位置;

 

步驟4:從左到右逐一比較兩個小數組中的元素,較小的元素先放入新數組,指針移位,直到lr指針超出尾部;

 

繼續比較寫入較小的元素到新數組

繼續比較寫入較小的元素到新數組

 

指針尚未移到尾部的數組,說明還有剩余元素,將剩余元素合並到新數組尾部。

 

步驟5:新建一個空數組存放合並結果,用lr兩個輔助指針記錄兩個數組當前操作位置;

 

步驟6:從左到右逐一比較兩個小數組中的元素,較小的元素先放入新數組,指針移位,直到lr指針超出尾部;

 

將較小的元素寫入到新數組

繼續比較寫入較小的元素到新數組

繼續比較寫入較小的元素到新數組

繼續比較寫入較小的元素到新數組

 

步驟7:右邊的指針尚未移到尾部的數組,說明還有剩余元素,將剩余元素合並到新數組尾部。

 

完成歸並排序,返回排好序的新數組

 

 

歸並排序復雜度

 

  • 時間復雜度:O(nlogn)

歸並排序把數組一層層折半分組,長度為 n 的數組,折半層數就是 logn,每一層進行操作的運算量是 n,得出時間復雜度 O(nlogn)。

  • 空間復雜度:O(n)

每次歸並操作需要創建額外的新數組,占用空間為 n,但這部分額外空間會隨着方法的結束而釋放,所以只需要算單次歸並操作開辟的空間即可,得出空間復雜度 O(n)。

  • 穩定性:穩定

從算法中從左到右逐一比較,較小的先放入新數組,所以兩個值相同的元素,排序后依然保持原先后順序。

 

 


免責聲明!

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



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