歸併排序 Merge sort

2021-10-04 19:39:04 字數 3952 閱讀 2097

結語歸併排序(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 相當於輸出...