有趣的事,Python永遠不會缺席!
一、歸並排序(MERGE-SORT)概念
歸並排序(MERGE-SORT)是建立在歸並操作上的一種有效的排序算法,該算法是采用分治法(Divide and Conquer)的一個非常典型的應用。歸並排序適用於子序列有序的數據排序。
1、原理
歸並排序是分治法的典型應用。分治法(Divide-and-Conquer):將原問題划分成 n 個規模較小而結構與原問題相似的子問題;遞歸地解決這些問題,然后再合並其結果,就得到原問題的解。從上圖看分解后的數列很像一個二叉樹。
歸並排序采用分而治之的原理:
- 將一個序列從中間位置分成兩個序列;
- 在將這兩個子序列按照第一步繼續二分下去;
- 直到所有子序列的長度都為1,也就是不可以再二分截止。這時候再兩兩合並成一個有序序列即可。
原理如上圖,圖片來源於https://blog.csdn.net/su_bao/article/details/81053871
2、舉例
- 對以下數組進行歸並排序:
[11, 99, 33 , 69, 77, 88, 55, 11, 33, 36,39, 66, 44, 22]
2. 首先,進行數組分組,即
[11, 99, 33 , 69, 77, 88, 55], [ 11, 33, 36,39, 66, 44, 22]
[11, 99, 33] , [69, 77, 88, 55], [ 11, 33, 36], [39, 66, 44, 22]
[11], [99, 33] , [69, 77], [88, 55],[ 11], [33, 36],[39, 66], [44, 22]
直到所有子序列的長度都為1,也就是不可以再二分截止。
[11], [99], [33] , [69], [77], [88], [55],[ 11], [33], [36],[39], [66], [44], [22]
3. 這時候再兩兩合並成一個有序序列即可。
[11],[33,99],[69,77],[55,88],[11],[33,36],[39,66],[22,44]
[11,33,99],[55,69,77,88],[11,33,36],[22,39,44,66]
[11,33,55,69,77,88,99],[11,22,33,36,39,44,66]
4、最終排序
1 [11, 11, 22, 33, 33, 36, 39, 44, 55, 66, 69, 77, 88, 99]
-
二、代碼
代碼用jupyternotebook實現
1 def merge_sort(arr): 2 """歸並排序""" 3 if len(arr) == 1: 4 return arr 5 # 使用二分法將數列分兩個 6 mid = len(arr) // 2 7 left = arr[:mid] 8 right = arr[mid:] 9 # 使用遞歸運算 10 return marge(merge_sort(left), merge_sort(right)) 11 12 13 def marge(left, right): 14 """排序合並兩個數列""" 15 result = [] 16 # 兩個數列都有值 17 while len(left) > 0 and len(right) > 0: 18 # 左右兩個數列第一個最小放前面 19 if left[0] <= right[0]: 20 result.append(left.pop(0)) 21 else: 22 result.append(right.pop(0)) 23 # 只有一個數列中還有值,直接添加 24 result += left 25 result += right 26 return result 27 28 merge_sort([11, 99, 33 , 69, 77, 88, 55, 11, 33, 36,39, 66, 44, 22]) 29 30 # 返回結果[11, 11, 22, 33, 33, 36, 39, 44, 55, 66, 69, 77, 88, 99]
這里記錄一下,python有一個模塊,專門提供了歸並排序的方法,叫做“heapq”模塊,因此我們只要將分解后的結果導入該方法即可。例如:
1 from heapq import merge 2 3 def merge_sort(lst): 4 if len(lst) <= 1: 5 return lst # 從遞歸中返回長度為1的序列 6 middle = len(lst) // 2 7 left = merge_sort(lst[:middle]) # 通過不斷遞歸,將原始序列拆分成n個小序列 8 right = merge_sort(lst[middle:]) 9 return list(merge(left, right)) 10 11 12 merge_sort([11, 99, 33 , 69, 77, 88, 55, 11, 33, 36,39, 66, 44, 22]) 13 14 # 返回結果[11, 11, 22, 33, 33, 36, 39, 44, 55, 66, 69, 77, 88, 99]
三、特點
-
比較性:排序時元素之間需要比較,所以為比較排序
-
穩定性:我們從代碼中可以看到當左邊的元素小於等於右邊的元素就把左邊的排前面,而原本左邊的就是在前面,所以相同元素的相對順序不變,故為穩定排序
-
時間復雜度: 復雜度為O(nlog^n)
-
空間復雜度:在合並子列時需要申請臨時空間,而且空間大小隨數列的大小而變化,所以空間復雜度為O(n)
-
記憶方法:所謂歸並肯定是要先分解,再合並
結果
Successfully !!!
有趣的事,Python永遠不會缺席!還不來加我,瞅什么瞅。