思路
我学习的归并是简单的二路归并,思路如下:
① 将数组平均分成两份
② 递归重复①,直到每个数组中只有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左右,在前端一般不会做如此大量数据的排序。
也可以选择将递归的方式改为迭代的方式来规避这个问题