結語歸併排序(merge-sort),典型的分治策略(divide and conquer)。核心思路是將整體序列一分為二形成兩個子串行,分別對子序列排序,再將兩個有序子串行合併成乙個有序序列。
思路如圖:
[外鏈轉存失敗,源站可能有防盜煉機制,建議將儲存下來直接上傳(img-c0sid4yi-1586172341721)(…/asset/image/article/image-20200405121524144.png)]
整體過程分為拆分和合併兩大階段。
拆分,核心問題是確定拆分位置即可,我們利用左右元素索引之和除2即可,也就是:mid = (left + right)/2
,指導拆分到子串行僅僅存在乙個元素的基本情形。
合併,merge 是歸併排序的核心,將兩個已排序子串行合併為乙個排序序列的過程。當子串行中僅存在乙個元素時,可視為子串行已經排序,因此我們的合併是從兩個單一元素子串行開始的。當子串行存在多個元素時,我們需要逐個得到當前最小元素,進而完成整體排序,過程中我們需要乙個臨時區來儲存已排序的部分。
合併思路如下圖所示,我們以合併 [2, 3, 5, 6, 8] 和 [0, 1, 4, 7, 9] 為例,進行演示:
[外鏈轉存失敗,源站可能有防盜煉機制,建議將儲存下來直接上傳(img-1bcejybp-1586172341723)(…/asset/image/article/image-20200405125342380.png)]
如圖,實現時,設定 i,j 分別儲存兩個子串行待比較元素索引。比較後,將小元素移動到臨時區,同時右移索引。當其中乙個子串行全部元素全部移動到臨時區後,另乙個子串行將後續元素直接移動到臨時區即可,不需要繼續比較。最後將臨時區已排序資料拷貝回原始序列即可。
// 歸併排序
func
mergesort
(data [
]int
)// @param data int 待排序切片整體
// @param left int 左元素索引
// @param right int 右元素索引
func
mergesort
(data [
]int
, left, right int)}
// @param data int 待排序切片整體
// @param left int 左元素索引
// @param mid int 中間分隔元素索引
// @param right int 右元素索引
func
merge
(data [
]int
, left, mid, right int
)else
// 遞增臨時索引
ti ++
}// 將左邊未移入臨時區的元素,移入
for i<=mid
// 將右邊未移入臨時區的元素,移入
for j <= right
// 將臨時區資料拷貝到 data 對應的位置
for ti=
0; left <= right;
}// 測試通過
data :=
intmergesort
(data)
fmt.
println
(data)
// [0 1 2 3 4 5 6 7 8 9]
# 歸併排序
defmergesort
(data)
: mergesort(data,0,
len(data)-1
)# @param data 待排序序列
# @param left 左索引
# @param right 右索引
defmergesort
(data, left, right)
:# 至少含有 1 個元素
if left < right :
# 計算 mid 中間分隔索引
mid =
(left + right)
>>
1# 歸併排序左邊
mergesort(data, left, mid)
# 歸併排序右邊
mergesort(data, mid+
1, right)
# 合併結果
merge(data, left, mid, right)
# 合併
# @param data 排序序列
# @param left 左索引
# @param mid 分隔索引
# @param right 右索引
defmerge
(data, left, mid, right)
:# 構建臨時資料區
temp =
# 初始化索引變數
i = left
j = mid +
1# 合併,左邊和右邊都存在未比較的元素時
while i <= mid and j <= right :
# 左邊小
if data[i]
<= data[j]:)
i +=
1else
:# 右邊小
) j +=
1# 左邊未比較元素放入臨時區
for _ in
range
(i, mid+1)
:)i +=
1# 右邊未比較元素放入臨時區
for _ in
range
(j, left+1)
:)j +=
1# 由臨時區拷貝回data
i = left
for ti in
range
(len
(temp)):
data[i]
= temp[ti]
i +=
1# 測試通過
data =[5
,3,8
,6,2
,7,4
,0,9
,1]mergesort(data)
print
(data)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
function
mergesort
(data)
function
mergesort
(data, left, right)
}function
merge
(data, left, mid, right)
else
}// 左邊未比較元素放入臨時區
while
(i <= mid)
// 右邊未比較元素放入臨時區
while
(j <= right)
// 由臨時區拷貝回data
for(
let i =
0; i < temp.length; i ++)}
// 測試通過
data =[5
,3,8
,6,2
,7,4
,0,9
,1]mergesort
(data)
console.
log(data)
// array(10) [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
// to be continued
從複雜度上看,合併操作的平均時間複雜度為o(n),拆分的二叉樹深度為lgn,總的平均時間複雜度為o(nlgn),並且最好和最壞情況的時間複雜度都為o(nlgn)。
從穩定性上看,data[i] <= data[j]
的元素間比較是穩定的。
參考:《演算法導論》第三版!
關注,紅牛慕課 傳送 演算法導論 獲取pdf。
歸併排序 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 相當於輸出...