简介
前面三种排序算法只有教学价值,因为效率低,很少实际使用。归并排序(Merge sort)则是一种被广泛使用的排序方法。
基本思想💡
将两个已经排序的数组合并,要比从头开始排序所有元素来得快。因此,可以将数组拆开,分成n个只有一个元素的数组,然后不断地两两合并,直到全部排序完成。
提示💡
依次两两比较两组元素,将小的放入结果数组。
算法实现
Javascript 简洁实现(推荐)
let mergeSort = (arr) => {
if (arr.length < 2) return arr;
let middle = parseInt(arr.length / 2),
left = arr.slice(0, middle),
right = arr.slice(middle);
return merge(mergeSort(left), mergeSort(right));
}
let merge = (left, right) => {
let result = [];
while (left.length && right.length) {
left[0] <= right[0] ?
result.push(left.shift()) :
result.push(right.shift());
}
while (left.length) result.push(left.shift());
while (right.length) result.push(right.shift());
return result;
}
阮一峰Javascript实现
- 合并函数
function merge(left, right){
var result = [],
il = 0,
ir = 0;
while (il < left.length && ir < right.length){
if (left[il] < right[ir]){
result.push(left[il++]);
} else {
result.push(right[ir++]);
}
}
return result.concat(left.slice(il)).concat(right.slice(ir));
}
上面的 merge 函数,合并两个已经按升序排好序的数组。首先,比较两个数组的第一个元素,将其中较小的一个放入 result 数组;然后,将其中较大的一个与另一个数组的第二个元素进行比较,再将其中较小的一个放入 result 数组的第二个位置。以此类推,直到一个数组的所有元素都进入 result 数组为止,再将另一个数组剩下的元素接着 result 数组后面返回(使用 concat 方法)。
有了 merge 函数,就可以对任意数组排序了。基本方法是将数组不断地拆成两半,直到每一半只包含零个元素或一个元素为止,然后就用 merge 函数,将拆成两半的数组不断合并,直到合并成一整个排序完成的数组。
function mergeSort(myArray){
if (myArray.length < 2) {
return myArray;
}
var middle = Math.floor(myArray.length / 2),
left = myArray.slice(0, middle),
right = myArray.slice(middle);
return merge(mergeSort(left), mergeSort(right));
}
上面的代码有一个问题,就是返回的是一个全新的数组,会多占用空间。因此,修改上面的函数,使之在原地排序,不多占用空间。
function mergeSort(myArray){
if (myArray.length < 2) {
return myArray;
}
var middle = Math.floor(myArray.length / 2),
left = myArray.slice(0, middle),
right = myArray.slice(middle),
params = merge(mergeSort(left), mergeSort(right));
// 在返回的数组头部,添加两个元素,第一个是0,第二个是返回的数组长度
params.unshift(0, myArray.length);
// splice用来替换数组元素,它接受多个参数,
// 第一个是开始替换的位置,第二个是需要替换的个数,后面就是所有新加入的元素。
// 因为splice不接受数组作为参数,所以采用apply的写法。
// 这一句的意思就是原来的myArray数组替换成排序后的myArray
myArray.splice.apply(myArray, params);
// 返回排序后的数组
return myArray;
}
ES6 实现
/**
* 归并排序:先分后合
* @param {*} arr
* @returns
*/
function mergeSort(arr) {
if (arr.length < 2) return arr;
let midddle = parseInt(arr.length / 2);
const left = arr.slice(0, midddle);
const right = arr.slice(midddle);
return merge(mergeSort(left), mergeSort(right));
}
const merge = (left, right) => {
let result = [];
//两两比较数组开头元素
while (left.length && right.length) {
left[0] <= right[0]
? result.push(left.shift())
: result.push(right.shift());
}
// 将剩余元素放入结果中
while (left.length) result.push(left.shift());
while (right.length) result.push(right.shift());
return result;
};
测试代码
let arr = [1, 5, 4, 3, 6, 8];
console.log("原数组", arr);
arr3 = mergeSort(arr);
console.log("归并排序:", arr);