歸併排序(merge sort)
平均時間複雜度: o(n
logn
)o( n log n)
o(nlog
n)空間複雜度: o(n
)o(n)
o(n)
穩定性:穩定
基本形式:
歸併排序是建立在歸併操作上的一種有效的排序演算法,將已有序的子串行合併,得到完全有序的序列,是分治演算法的典型應用。常用的將兩個有序序列合併成乙個有序序列的演算法稱為二路歸併。
如何使子串行有序?
要將有序的子串行進行合併,首先要得到有序的子串行。這就是分治演算法的「分」的過程。先將完全序列中的每乙個數都分為乙個子串行,也就是每乙個子串行中只有乙個數,本身即是有序,就可以開始合併操作了。這是從上到下的過程,就形成了一棵樹。
如何合併?
這就是分治演算法中的「治」。對於兩個有序的子串行,我們將其合併即可,這樣就需要額外的儲存空間。這個o(n
)o(n)
o(n)
的額外儲存空間可以事先申請好,也可以使用的時候用多少申請多少。
為什麼歸併排序在最好情況和最壞情況下的時間複雜度都是o(n
logn
)o(n log n)
o(nlog
n)?因為歸併排序,先要「分」,這個過程就構成一棵樹,以二路歸併為例,n個數的序列要分成n個有序子串行要分成 log
2n
log_2n
log2n
層(樹的深度),在」治「的過程中,每一層的平均時間複雜度為o(n
)o(n)
o(n)
,故整體的平均時間複雜度為nlo
g(n)
n log(n)
nlog(n
)。不管原始序列是否有序,故按照這個步驟進行操作,時間複雜度都是一樣的。
實現遞迴
def
merge_sort
(array):if
len(array)
<=1:
return array
middle =
len(array)//2
array1 = merge_sort(array[
:middle]
) array2 = merge_sort(array[middle:])
result =
i,j =0,
0while
(i <
len(array1)
and j <
len(array2)):
#注意這裡是小於等於,保證穩定性
if array1[i]
<= array2[j]:)
i +=
1else:)
j +=
1 result += array1[i:
]+ array2[j:
]return result
迭代
迭代的思想也是分組排序,然後合併, 我們用乙個視窗,視窗的長度從2到(le
n(ar
ray)
)+1/
/2
(len(array))+1//2
(len(a
rray
))+1
//2, 在每個視窗內都需要額外的空間輔助排序。**總體分為兩個部分,merge 函式用來合併有序數組成新的更長的有序陣列,主函式用來用視窗掃瞄陣列然後呼叫merge函式合併陣列。
def
merge_sort
(array)
:def
merge
(array, low, middle, high)
:# 用middle 指標將low和high的陣列分成兩個陣列 left array[low: middle] right array[middle: high]
low_array = array[low: middle]
high_array = array[middle:high+1]
low_idx, high_idx, array_idx =0,
0, low
while
(low_idx <
len(low_array)
and high_idx <
len(high_array)):
if low_array[low_idx]
<= high_array[high_idx]
: array[array_idx]
= low_array[low_idx]
low_idx +=
1else
: array[array_idx]
= high_array[high_idx]
high_idx +=
1 array_idx +=
1 array[array_idx:high+1]
= low_array[low_idx:
]+ high_array[high_idx:
]
step =
1while step <
(len
(array)):
low =
0while
(low <
len(array)):
middle = low + step
high =
min(low + step *2-
1,len(array)-1
)if middle <= high:
merge(array, low, middle, high)
low += step*
2 step *=
2return array
這裡一定要用middle指標,不能用low 和 high除以2,因為在邊界的時候可能不能均分成兩個陣列(比如長度6,分成了左四右二的有序陣列)
改進如果子陣列較小(7左右),則採用速度更快的插入排序。這樣做,會帶來一定的好處,例如歸併排序減少分配、**臨時儲存區域的頻次,快速排序減少遞迴層次等。
檢測待歸併的兩個子陣列是否已經有序,如果已經有序則直接複製該子陣列;
特殊情況的處理,比如當前的兩個子串行中,左邊的最大值小於右邊的最小值,可以直接返回;或者嘴邊的最小值大於右邊的最大值,左右互換即可。
歸併排序 Merge sort
merge the a s.m and a m 1.t to r s.t template void two merge typet a,typet r,int s,int m,int t while i m r k a i while j t r k a j merge the a 0.n 1 s...
歸併排序(merge sort)
歸併排序 歸併排序是一種遞迴排序演算法,無論陣列元素的原始順序如何,其效能恆定不變。將陣列一分為二,分別排序兩部分元素,再將有序的兩半陣列歸併為乙個有序陣列。歸併步驟比較陣列前一半的元素與陣列的後一半元素,並將較小元素移到臨時陣列,該過程繼續前進,直到其中一半再沒有元素為止。此後只需將其餘元素移到臨...
歸併排序 Merge Sort
歸併排序 merge sort 是利用 歸併 技術來進行排序。歸併是指將若干個已排序的子檔案合併成乙個有序的檔案。兩路歸併演算法 1 演算法基本思路 設兩個有序的子檔案 相當於輸入堆 放在同一向量中相鄰的位置上 r low.m r m 1.high 先將它們合併到乙個區域性的暫存向量r1 相當於輸出...