python實現歸並排序,歸並排序的詳細分析。
學習歸並排序的過程是十分痛苦的。它並不常用,看起來時間復雜度好像是幾種排序中最低的,比快排的時間復雜度還要低,但是它的執行速度不是最快的。
很多朋友不理解時間復雜度低為什么運行速度不一定快,這個不清楚的伙伴可以看下我之前發表的文章http://www.cnblogs.com/Lin-Yi/p/7301535.html
看完之后也許你會對時間復雜度有一個新的認識。
我談的觀點往往不是官方的定義,我希望能幫助更多基礎薄弱的同學讀懂思想~
歸並排序:
先分開再合並,分開成單個元素,合並的時候按照正確順序合並
假如我們有一個n個數的數列,下標從0到n-1
首先是分開的過程
1 我們按照 n//2 把這個數列分成兩個小的數列
2 把兩個小數列 再按照新長度的一半 把每個小數列都分成兩個更小的
。。。一直這樣重復,一直到每一個數分開了
比如: 6 5 4 3 2 1
第一次 n=6 n//2=3 分成 6 5 4 3 2 1
第二次 n=3 n//2=1 分成 6 5 4 3 2 1
第三次 n=1的部分不分了
n=2 n//2=1 分成 5 4 2 1
之后是合並排序的過程:
3 分開之后我們按照最后分開的兩個數比較大小形成正確順序后組合綁定
剛剛舉得例子 最后一行最后分開的數排序后綁定 變成 4 5 1 2
排序后倒數第二行相當於把最新分開的數排序之后變成 6 4 5 3 12
4 對每組數據按照上次分開的結果,進行排序后綁定
6 和 4 5(兩個數綁定了) 進行排序
3 和 1 2(兩個數綁定了) 進行排序
排完后 上述例子第一行待排序的 4 5 6 1 2 3 兩組數據
5 對上次分開的兩組進行排序
拿着 4 5 6 1 2 3兩個數組,進行排序,每次拿出每個數列中第一個(最小的數)比較,把較小的數放入結果數組。再進行下一次排序。
每個數組拿出第一個數,小的那個拿出來放在第一位 1 拿出來了, 變成4 5 6 2 3
每個數組拿出第一個書比較小的那個放在下一個位置 1 2被拿出來, 待排序 4 5 6 2
每個數組拿出第一個書比較小的那個放在下一個位置 1 2 3 被拿出來, 待排序 4 5 6
如果一個數組空了,說明另一個數組一定比排好序的數組最后一個大 追加就可以結果 1 2 3 4 5 6
相當於我們每次拿到兩個有序的列表進行合並,分別從兩個列表第一個元素比較,把小的拿出來,在拿新的第一個元素比較,把小的拿出來
這樣一直到兩個列表空了 就按順序合並了兩個列表
結束
時間復雜度: 最好最壞都是 O( n log n )
穩定性:穩定
缺點:每次拆分數組都要開心的數組, 每次合並數組都要開新數組,空間復雜度很大
在python中這樣實現
def merge_sort( li ): #不斷遞歸調用自己一直到拆分成成單個元素的時候就返回這個元素,不再拆分了 if len(li) == 1: return li #取拆分的中間位置 mid = len(li) // 2 #拆分過后左右兩側子串 left = li[:mid] right = li[mid:] #對拆分過后的左右再拆分 一直到只有一個元素為止 #最后一次遞歸時候ll和lr都會接到一個元素的列表 # 最后一次遞歸之前的ll和rl會接收到排好序的子序列 ll = merge_sort( left ) rl =merge_sort( right ) # 我們對返回的兩個拆分結果進行排序后合並再返回正確順序的子列表 # 這里我們調用拎一個函數幫助我們按順序合並ll和lr return merge(ll , rl) #這里接收兩個列表 def merge( left , right ): # 從兩個有順序的列表里邊依次取數據比較后放入result # 每次我們分別拿出兩個列表中最小的數比較,把較小的放入result result = [] while len(left)>0 and len(right)>0 : #為了保持穩定性,當遇到相等的時候優先把左側的數放進結果列表,因為left本來也是大數列中比較靠左的 if left[0] <= right[0]: result.append( left.pop(0) ) else: result.append( right.pop(0) ) #while循環出來之后 說明其中一個數組沒有數據了,我們把另一個數組添加到結果數組后面 result += left result += right return result if __name__ == '__main__': li = [5,4 ,3 ,2 ,1] li2 = merge_sort(li) print(li2)
算法過程理解起來非常痛苦 嗚嗚!好委屈
不過我希望大家靜下心來一點點學,一定會有所收獲!