歸並排序采用的是分治的思想,首先是“分”,將一個數組反復二分為兩個小數組,直到每個數組只有一個元素;其次是“治”,從最小數組開始,兩兩按大小順序合並,直到並為原始數組大小,下面是圖解:
分”就是將原始數組逐次二分,直到每個數組只剩一個元素,一個元素的數組自然是有序的,所以就可以開始“治”的過程了。
時間復雜度分析:分的過程需要三步:log8 = 3,而每一步都需要遍歷一次8個元素,所以8個元素共需要運行 8log8 次指令,那么對於 n 個元素,時間復雜度為 O(nlogn)。
“治”實際上是將已經有序的數組合並為更大的有序數組。那怎么做呢?就是創建一個新數組,比較left[0]和right[0] ,那個比較小就將那個的值放進新數組,然后再繼續比較left[0]和right[1],或者是left[1]和right[0]。可以看出數組left,right都只需遍歷一遍,所以對兩個有序數組的排序的時間復雜度為O(n)。
一、遞歸分解
二、合並為有序數組
三、js代碼實現
function mergeSort (arr) { let len = arr.length if (len < 2) { return arr } let middle = Math.floor(len/2)
//拆分成兩個子數組
let left = arr.slice(0, middle) let right = arr.slice(middle,len) //遞歸拆分
let mergeSortLeft = mergeSort(left) let mergeSortRight = mergeSort(right) //合並
return merge( mergeSortLeft,mergeSortRight) } const merge = (left, right) => { const result = []; while (left.length && right.length) { // 注意: 判斷的條件是小於或等於,如果只是小於,那么排序將不穩定.
if (left[0] <= right[0]) { result.push(left.shift()); //每次都要刪除left或者right的第一個元素,將其加入result中
} else { result.push(right.shift()); } } //將剩下的元素加上
while (left.length) result.push(left.shift()); while (right.length) result.push(right.shift()); return result; };