基本思想:
对数组采用先分后合并的方式。
时间复杂度 nlogn
简单说明:
对一个数组,首先是分,将一个数组反复二分为两个小数组,直到每个数组只有一个元素。然后是合,从最小数组开始,两两按大小顺序合并,直到并为原始数组大小
下面提供两种实现方式
1.递归版:
//归并排序(递归版)
function mergeArray(arr) {
//分割数组(归)
if(arr.length < 2){
return arr;
}
//找到中间值
var mid = Math.floor(arr.length / 2);
//逐一分割
var left = arr.slice(0,mid);
var right = arr.slice(mid);
if(!left && !right){
return false;
}
//并
function merge(left,right) {
var result = [];
//比较左右两个数组,采用队列思想,分别比较队头,小的出队进入结果数组,然后继续比较,
//最终返回的数组是从小到大排列的,以此作为合并过程中局部排列好的数组。
while(left.length && right.length){
if(left[0] <= right[0]){
result.push(left.shift());
}else{
result.push(right.shift());
}
}
return result.concat(left).concat(right);
}
return merge(mergeArray(left),mergeArray(right));
}
非递归法:
由于递归深度过高,对于较大的数组容易造成溢出,因此非递归的方式执行会更友好。
//归并排序(非递归版)
function mergeArray(arr){
if(arr.length < 2){
return arr;
}
//归
var step = 1; //从二分开始,逐渐到4分,最终达到数组长度
var left,right;
while(step < arr.length){
left = 0;
right = step;
while(right <= arr.length){
//并
//逐一找到相邻需要比较的数组,比如当step=1的时候,下面需要依次比较(0,1),(2,3)序列位置的数
merge(left,right,arr,step);
left = right+step; //右移
right = left+step;
}
step *= 2;
}
//并(对左右序列进行排序
function merge(left,right,arr,step){
//获取需要比较的左右数组
var left_arr = arr.slice(left,left+step);
var right_arr = arr.slice(right,right+step);
var m = 0;
var n = 0;
for(var i = left;i < right+step; i++){
if( m < left_arr.length && n < right_arr.length){
if(left_arr[m] <= right_arr[n]){
arr[i] = left_arr[m];
m++;
}else{
arr[i] = right_arr[n];
n++;
}
}else if(m < left_arr.length){
arr[i] = left_arr[m];
m++;
}else if(n < right_arr.length){
arr[i] = right_arr[n];
n++
}
}
}
return arr;
}