歸併排序採用了分治策略,在對數組進行排序的時候,先將數組分割成更小的子數組,而後對子數組排序,最後排序後的子數組合併成一個完成的數組,在對子數組排序的時候能夠使用相同的策略繼續對子數組進行分割,直到子數組中只包含一個元素。
例如咱們須要數組[3,2,6,4,8,1,7,5]排序,首先將數組分割成只包含單個元素的子數組:數組
[3] [2] [6] [4] [8] [1] [7] [5]
將相鄰的兩個子數組合並,獲得包含兩個元素的已排序子數組:函數
[2, 3] [4, 6] [1, 8] [5, 7]
繼續兩兩合併:spa
[2, 3, 4, 6] [1, 5, 7, 8]
最終就能夠獲得一個完成的排序好的數組了:3d
[1, 2, 3, 4, 5, 6, 7, 8]
下面看一下怎麼用JS代碼實現一個歸併排序。
首先看一下怎麼合併兩個已排序的子數組,代碼以下:code
/** * 輔助方法,合併數組arr中的兩個已排序的子數組 * 做爲例子只考慮從小到大排序,其餘排序可自定義比較函數,相似於Array#sort * @param {*} arr 數組 * @param {*} start 起始位置 * @param {*} end 結束位置(包含在範圍內) * @param {*} mid 兩個子數組的分割位置 */ function merge(arr, start, end, mid) { // 須要合併的元素個數 const count = end - start + 1; // 左側已排序數組 const left = arr.slice(start, mid + 1); // 右側已排序數組 const right = arr.slice(mid + 1, end + 1); // 加入守衛元素,這樣能夠不用判斷子數組是否爲空 left.push(Infinity); right.push(Infinity); // 依次取出兩個子數組中的較小的值 let i = 0; let l = 0; let r = 0; while(i < count) { if (left[l] < right[r]) { arr[start + i] = left[l]; l++; } else { arr[start + i] = right[r]; r++; } i++; } }
能夠把兩個已排序的子數組看做是兩堆撲克,每次從兩隊撲克中取出較小的一張牌,直到全部的牌取完,獲得的就是一副排好序的撲克。blog
下面看一下如何使用遞歸實現歸併排序:
首先計算出中心點將數組分割成兩個子數組,對兩個子數組分別排序,最後調用merge函數將兩個已排序的子數組合並獲得最終的排序數組。排序