前端工程師算法系列(4)-歸併排序
歸併排序
一、原理解析
歸併排序不像前面講過的幾個排序那樣直觀,為了便於理解,我們先做個問題分解。
假設有兩個已經排序好 的陣列:
let arrLeft = [1, 3, 4, 7] let arrRight = [2, 5, 6, 9]
如何把這兩個已排序好的陣列 合併成一個排序好 的陣列呢?
可以新建一個空陣列arrResult,比較arrLeft 第一位和 arrRight 第一位,哪個小就把這個陣列的第一位拿出來push到空數組裡。然後反覆執行上面的邏輯,直到arrLeft或者arrRight其中一個變為空陣列。最後再把另一個不為空的全部拿出來 push 到arrResult。 以下是程式碼:
function merge(leftArr, rightArr) { var resultArr = [] while(leftArr.length && rightArr.length) { resultArr.push(leftArr[0] <= rightArr[0] ? leftArr.shift() : rightArr.shift()) } return resultArr.concat(leftArr).concat(rightArr) }
那回頭看看我們要真實解決的問題,如何對一個未排序的陣列進行排序呢?
對於如下陣列:
let arr = [4, 1, 2, 6, 9, 7, 3, 5]
我們可以把陣列分成兩部分:
let part1 = [4, 1, 2, 6] let part2 = [9, 7, 3, 5]
假設我們已經寫好了我們最終要實現的排序方法 mergeSort。那麼 mergeSort(arr) 等價於 merge(mergeSort(part1), mergeSort(part2)) 。 即:對陣列 arr 的排序,等價於把陣列分兩部分分別對每部分排序得到兩個排序的陣列,然後再利用剛剛寫好的merge 方法把兩個已經排序好的數組合併成一個最終排序好的陣列。
function mergeSort() { //待補充 } mergeSort(arr) //等價於 merge(mergeSort(part1), mergeSort(part2))
要排序一個大陣列,可以把這個大陣列拆分成兩個小陣列,把問題轉變成分別排序這兩個小陣列,再把排序後的小陣列通過簡單的方式合併已排序的大陣列。 可是如何排序這兩個小陣列呢?迴圈剛剛的邏輯,直到陣列拆分到極小(陣列長度為1,排序的結果就是自己)。
二、程式碼實現
以下是 JavaScript 版本的的程式碼實現:
function mergeSort(arr) { var merge = function(leftArr, rightArr) { var resultArr = [] while(leftArr.length && rightArr.length) { resultArr.push(leftArr[0] <= rightArr[0] ? leftArr.shift() : rightArr.shift()) } return resultArr.concat(leftArr).concat(rightArr) } if(arr.length < 2) return arr let mid = arr.length >> 1//取陣列的中位下標,也可以用 parseInt(arr.length/2) return merge(mergeSort(arr.slice(0, mid)), mergeSort(arr.slice(mid))) }
三、複雜度
平均時間複雜度為 O(nlogn),效能極好。
四、參考
ofollow,noindex">維基百科-歸併排序本文作者:若愚。如果你覺得不錯,或者發現文章中的錯誤,或者有更好的建議,歡迎演算法交流群交流,掃碼進群(如無法掃描進群,加微信:hungervalley 拉入群)。
點選掃碼進微信群