归并排序算法,先看以下一张图:
结合图片看过程:
- 从上往下,把数组1/2等分,然后再1/2等分。。。
- 从下往上,在合并的时候,会对等分的数组进行比较,用上图的Level 1说明:
左侧是[i,mid],右侧是[j,right],上级的是[left,right]
首先,i索引 位置的值和 j索引 位置的值比较,小的值放到 k索引 的位值,小的值的 索引 自增,k索引 自增
有一种临界情况,当 i>mid ,或者 j>right,说明等分数组有一边已经遍历完成,遍历完成的数组之后不再需要自增了,k的值取没有完成遍历的
看具体实现代码:
sortMerge.js
// 归并排序
window.sortMerge = {
_mergeSort(arr,l,mid,r) {
var tmp = [];
for (var i=l; i<=r; i++) {
tmp.push(arr[i]);
}
//
for (var i=l,j=mid+1,k=l; k<=r; k++) {
if (i>mid) {
arr[k] = arr[j];
j++;
} else if (j>r) {
arr[k] = arr[i];
i++;
} else if (arr[i]<arr[j]) {
arr[k] = arr[i];
i++;
} else {
arr[k] = arr[j];
j++;
}
}
},
_merge(arr,l,r) {
let mid = Math.floor((l+r)/2);
// if (l>=mid) return;
// 数组足够小,用插入排序
if (r-l<=10) {
sortBasic.insert_limit({arr,l,r});
return;
}
sortMerge._merge(arr, l, mid);
sortMerge._merge(arr, mid+1, r);
// 优化,两边都排序完成,mid<=mid+1的值,不需要执行
if (arr[mid]>arr[mid+1]) {
sortMerge._mergeSort(arr,l,mid,r);
}
},
merge({arr, orderby="asc"}) {
sortMerge._merge(arr, 0, arr.length-1);
return arr;
},
mergeBU({arr, n}) {
n = n ? n : arr.length-1;
for (var sz=1; sz<=n; sz+=sz) {
for (var i=0; i+sz<n; i+=sz+sz) {
sortMerge._mergeSort(arr, i, i+sz-1, Math.min(i+sz+sz-1, n-1));
}
}
return arr;
}
}
test.js 追加(请先看算法-基础篇)
let {
merge,
} = sortMerge;
// test4 插入排序vs并归排序,并归效率非常高
// testSort({arr:arr1, fn:insert});
// testSort({arr:arr2, fn:merge});
//test5 插入排序vs并归排序,数据源接近有序的:效率都非常高,插入排序相对用时少些
// testSort({arr:arr3, fn:insert});
// testSort({arr:arr4, fn:merge});
mergeBU方法和_merge方法接近,区别是自底而上。