思路
我學習的歸併是簡單的二路歸併,思路如下:
① 將陣列平均分成兩份
② 遞迴重複①,直到每個陣列中只有1個元素,只有一個元素的陣列可以認為是排好序的
③ 將兩個排好序的陣列合併成一個排好序的陣列
④ 重複③直到最終得到一個排好序的陣列
javascript實現
/** * 歸併排序 * @param arr * @returns */ function mergeSort(arr){ if(!(arr instanceof Array)){ return []; } if(arr.length<=1){ return arr; } var left=arr.splice(0,Math.floor(arr.length/2)), right=arr, res=[]; left=mergeSort(left); right=mergeSort(right); //一次歸併,認為左右兩邊的陣列是排序好的,通過這種方式將它們合成為一個排序好的陣列 //只有一個元素的陣列可以認為是已經排序好的,所以通過: //left=mergeSort(left); //right=mergeSort(right); //兩步遞迴得到拆分為一個元素的陣列,再通過下面的歸併得到結果 while(left.length && right.length){ left[0]>right[0] ? res.push(right.shift()): res.push(left.shift()); } //歸併剩下的元素都是比res中的大的,直接拼接到後邊就好了 res=res.concat(left,right); return res; }
其他
在一些文章裡邊看到有人認為瀏覽器中,採用遞迴函式呼叫的方式實現演算法有棧溢位的風險。
因為函式每次呼叫都會產生一個上下文,放在上下文棧中,執行完畢後才會清除。但是遞迴呼叫會導致很多個上下文物件,這樣如果待排序的陣列過長,在某些瀏覽器下可能會發生棧溢位的錯誤。
測試瀏覽器上下文棧上限的程式碼:
var cnt = 0; try { (function() { cnt++; arguments.callee(); })(); } catch(e) { console.log(e.message, cnt); }
我測試過後發現主流瀏覽器的上下文棧長度上限都能達到2w左右,在前端一般不會做如此大量資料的排序。
也可以選擇將遞迴的方式改為迭代的方式來規避這個問題