歸併排序
一、思路(遞迴)
list = [a,b,c,d]
1、 遞迴過程
1、陣列一分為2,list1 = [a,b] list2 = [c,d]
2、先確立遞迴項:分別對list1/list2做歸併排序,此時可以假設左右子陣列已經有序。
3、執行merge子過程,將list1/list2合併並使之有序。
3、在程式首部新增基準條件:當前候選陣列長度為1,直接return,停止向下遞迴。
經典的歸併排序,目標陣列採用閉區間來標記,即[left,right],各標記定義如下:
陣列長度 n=7
index 0 1 2 3 4 5 6
value 3 2 5 | 7 1 3 6
標記 left mid right
注:n = 7
left = 0
right = n -1
mid = right // 2
2、merge子過程
1、函式傳入整個陣列,要merge的子陣列區間範圍[left,mid],[mid+1,right]
2、做完整陣列的切片 a=list[left,right+1]
3、設定內部指標i遍歷子陣列1,j遍歷子陣列2
指標k遍歷賦值給完整陣列
二、實現
from sort_helper import test_sort,random_array
def __merge(array, left, mid, right):
temp = array[left:right+1]
#新陣列temp的左中右標記,充當常量
n = len(temp)
l = 0
r = n-1
m = l + (r -l) // 2
#左陣列標記i,右陣列標記j,賦值外部迴圈標記k
i = 0
j = m + 1
#遍歷【0,n)即整個陣列長度,每次確定乙個下標應該賦值的元素並完成賦值操作
k = 0
while k < n:
#2、定義判斷條件,防越界;迴圈的次數是由n確定的,不存在i,j同時越界的情況
if i > m:
array[k + left] = temp[j]
j += 1
elif j > r:
array[k + left] = temp[i]
i += 1
#1、判斷兩個子陣列當前位置的值,並賦值給原陣列array的對應位置,此處可能涉及到越界問題,所以迴圈主體開始之前要判斷一下
elif temp[i] < temp[j]:
array[k + left] = temp[i]
i += 1
else:
array[k + left] = temp[j]
j += 1
k += 1
#錯誤示範
def __merge1(array, left, mid, right):
#錯誤1,開闢陣列空間只針對一部分元素,而非整個陣列
temp = array[:]
#錯誤2,left應該最後賦值為0,否則後兩部相當於減0,無作用
#錯誤3:內部端點就應該重新定義為l、r、mid;一旦否則array[k+left]無效果,因為left已變..
left = 0
mid = mid - left
right = right - left
n = right - left + 1
i = 0
j = mid + 1
k = 0
while k < n:
if i > mid:
array[k + left] = temp[j]
j += 1
elif j > right:
array[k + left] = temp[i]
i += 1
elif temp[i] < temp[j]:
array[k + left] = temp[i]
i += 1
else:
array[k + left] = temp[j]
j += 1
k += 1
print(array)
#該私有函式需要左右下標
def __merge_sort(array, left, right):
#3、新增基準條件,左右區間短點,相差1即可,即子陣列長度為1
if right -left <= 0:
return
#1、一分為二
mid = left + (right -left) // 2
#2、左右分別歸併排序,應該考慮到要新增基準條件了,否則無限遞迴
__merge_sort(array, left, mid)
__merge_sort(array, mid+1, right)
#4、此時,array兩個子陣列都已有序,但整個陣列卻還無序,需要合併
__merge(array, left, mid, right)
def merge_sort(array):
#作為帶外暴露的歸併排序函式,不需要左右下標
__merge_sort(array, 0, len(array)-1)
if __name__ == '__main__':
array = random_array()
test_sort('merge_sort', merge_sort, array)
三、優化
1、提前終止不必要的merge操作
def __merge_sort1(array, left, right):
#3、新增基準條件,左右區間短點,相差1即可,即子陣列長度為1
if right -left <= 0:
return
#1、一分為二
mid = left + (right -left) // 2
#2、左右分別歸併排序,應該考慮到要新增基準條件了,否則無限遞迴
__merge_sort1(array, left, mid)
__merge_sort1(array, mid+1, right)
#4、此時,array兩個子陣列都已有序,但整個陣列卻還無序,需要合併
if array[mid] > array[mid+1]:
__merge(array, left, mid, right)
def merge_sort1(array):
#作為帶外暴露的歸併排序函式,不需要左右下標
__merge_sort1(array, 0, len(array)-1)
2、使用插入排序優化def __merge_sort2(array, left, right):
if right -left <= 50:
insert_sort(array, left, right)
#必須要有return,否則無限遞迴
return
mid = left + (right -left) // 2
__merge_sort2(array, left, mid)
__merge_sort2(array, mid+1, right)
if array[mid] > array[mid+1]:
__merge(array, left, mid, right)
def merge_sort2(array):
__merge_sort2(array, 0, len(array)-1)
3、測試用例if __name__ == '__main__':
優化效果在有序性較強的情況下比較明顯
歸併排序(合併排序) 遞迴法
參考了一些大佬的 再自己總結了一下。原理基本不變。歸併排序 合併排序 是一種分治演算法。這個演算法不斷地將乙個陣列分為兩部分,分別對左子陣列和右子陣列排序,然後將兩個陣列合併為新的有序陣列。穩定 是 時間複雜度 最優 o nlog n 最差 o nlog n 平均 o nlog n include ...
歸併排序演算法 遞迴法
首先乙個問題,如何將兩個整數進行公升序排序?這不簡單嗎。將兩個數比較,再將小的放在前面,大的放在後面。然後如何將兩個公升序的陣列排序為乙個陣列呢?我知道我知道 建立第三個陣列,將需要那兩個陣列按下標順序進行比較,然後將小的數放入第三個陣列中,在將兩者下標加一。如,將a陣列與b陣列的第乙個元素比較,假...
歸併排序遞迴實現
include include define length 10 using namespace std void merge int ar,int br,int start,int mid,int end else if i mid else void copy int ar,int br,int...