分治法:归并排序
歸并排序的思想:
對集合的排序,可以看成他們子集合的分別排序,然后把各個有序的子集合合并成有序的全集,這里一般把原集合盡可能的均分為2個子集合。
可以看出這里有兩個工作量,一是把原數組不斷的對半切,直到子問題足夠小可以直接解出,二是把兩個有序的數組合并成一個有序的數組。
def MergeSort(arr,N):# 遞歸出口,出口需要返回當前的那個數if N == 1:return arr# 以下當作某一層的處理middle = N //2# 獲取待排序的兩個已排序的數組left_list = MergeSort(arr[:middle],len(arr[:middle]))right_list = MergeSort(arr[middle:],len(arr[middle:]))# 如下是針對兩個已排序的數組合并成一個有序數組的排列方法,為最基本的雙針模型i ,j =0,0result =[]while i < len(left_list) and j < len(right_list):if left_list[i] <= right_list[j]:result.append(left_list[i])i +=1else:result.append(right_list[j])j += 1result += left_list[i:]result += right_list[j:]# 返回已排序的結果,用于上一層獲取待排序的有序數組return result我們想一下可以發現,對半切這個操作可以省略掉,對半切是為了切成大小為1的肉丁,但是數組本來就是已經切好了的,那我們一個直接開始合并的操作,兩兩合并,四四合并,…
def MergeSort_iteration(arr):# 把一個數組arr[left:mid+1]和arr[mid+1:right+1]排成一個有序的序列,最后結果還是在# arr里def sorting_two_sorted_arr_in_place(arr,left,mid,right):left_list = arr[left:mid+1]right_list = arr[mid+1:right+1]i ,j =0,0result =[]while i < len(left_list) and j < len(right_list):if left_list[i] <= right_list[j]:result.append(left_list[i])i +=1else:result.append(right_list[j])j += 1result += left_list[i:]result += right_list[j:] arr[left:right+1] = result[:]# 雙針模型自然合并排序# 最外面的大的指針,1,2,4,8,16,32...,直到大于len(arr) cur_size = 1# 終止條件為超過了數組長度,前半部分為2的i次方,后半部分為2的i次方到endwhile cur_size < len(arr):# 內部循環,用于更新每一塊的順序,只要一個left指針就可以更新每一個局部left = 0# 截至條件同樣是left越界while left < len(arr)-1:# mid的位置,-1為數組是從0開始,簡單分析一個實例就明白了mid = left + cur_size -1# right的位置,一般情況下是mid + cur_size,同樣不能越界,越界時區len(arr)-1right = (mid + cur_size,len(arr)-1)[mid + cur_size>len(arr)-1]# 把制定區域的數排列有序sorting_two_sorted_arr_in_place(arr,left,mid,right)# 更新下一塊,每一個固定cur_size循環里面的步長為2倍cur_sizeleft += 2*cur_size# 更新外部循環的步長cur_size *=2return arr運行結果
arr = [7,3,66,33,22,66,99,0,1] print(arr) print(MergeSort(arr,len(arr))) print(MergeSort_iteration(arr))[7, 3, 66, 33, 22, 66, 99, 0, 1] [0, 1, 3, 7, 22, 33, 66, 66, 99] [0, 1, 3, 7, 22, 33, 66, 66, 99]我們還直到歸并排序的時間復雜度為O(nlogn),而且還是穩定的,排序問題的時間下界就是nlogn,歸并是一個漸近最優算法,為什么歸并排序是一個漸近最優算法?這涉及到排序的本質,排序的本質是消除逆序對,假如逆序對沒有了,整個數組就已經有序了,歸并排序先消除局部的逆序對,再消除全局的逆序對,這樣可以減少不必要的操作。為什么歸并是一個穩定的算法,歸并排序先消除局部的逆序對,再消除全局的逆序對,這樣不會理論上造成不穩定。
總結
- 上一篇: 分治:分治和动态规划的区别,二分检索递归
- 下一篇: 分治法:快速排序,3种划分方式,随机化快