起因,昨天取面试猿题库,两个面试官,每人各只考了两道算法题.
其中有一道是考归并排序不使用递归或是栈结构实现,感觉手生,当时答得并不好,傻傻地问面试官,不能考个"快排"吗,面试官笑笑:"快排"太简单....
1 传统方法,利用递归
归并排序其实要做两件事:
(1)“分解”——将序列每次折半划分。
(2)“合并”——将划分后的序列段两两合并后排序。
真的就只有这两件事.
我们先去解决"合并": 将两个有序数组,合并为一个.
function merge(arr1,arr2){ //代码思想,是借用<剑指offer>中合并两个有序单链表
if(!Array.isArray(arr1) || !Array.isArray(arr2)){
return;
}
var result = [];
function mergeInner(arr1,arr2){
if(arr1.length == 0){
result = result.concat(arr2);
return;
}else if(arr2.length == 0){
result = result.concat(arr1);
return;
}
if(arr1[0] < arr2[0]){
result.push(arr1.shift());
mergeInner(arr1,arr2);
}else{
result.push(arr2.shift());
mergeInner(arr1,arr2);
}
}
mergeInner(arr1,arr2);
return result;
}
有了上述基础之后,我们开始构思如何将一个数组分解成两个部分:
经过在指上演算,我们确定 var mid = Math.floor((arr.length-1)/2);
function mergeSort(arr){
if(arr.length == 1){
return arr;
}
var mid = Math.floor((arr.length-1)/2);
var left = arr.slice(0,mid+1);
var right = arr.slice(mid+1);
return merge(mergeSort(left), mergeSort(right));
}
2 不使用递归
参考http://book.51cto.com/art/201108/287079.htm 这个网站的算法图示很好,能帮助理解
非递归并归排序的第一步:非递归地合并两个有序数组
思路:代码自己解释自己好了,js代码本来就是那么简单
function merge(arr1,arr2){
if(typeof arr1 == "number"){
arr1 = [arr1];
}
if(typeof arr2 == "number"){
arr2 = [arr2];
}
var result = [];
while(arr1.length!=0 && arr2.length!=0){
if(arr1[0]<arr2[0]){
result.push(arr1.shift());
}else{
result.push(arr2.shift());
}
}
if(arr1.length==0){
return result.concat(arr2);
}else if(arr2.length==0){
return result.concat(arr1);
}
}
思路:我还是不想解释,程序员真的懒得写注释啊。。。
function mergeSort(arr){
while(arr.length != 1){
var temp = [];
if(arr.length%2==0){
for(var i=0;i<arr.length;i+=2){
temp.push(merge(arr[i],arr[i+1]));
}
}else{
for(var i=0;i<arr.length-1;i+=2){
temp.push(merge(arr[i],arr[i+1]));
}
temp.push(arr[arr.length-1]);
}
arr = temp;
}
return arr[0];
}
console.log(mergeSort([1,2,5,3,4])); //通过!!!