归并排序采用了分治策略,在对数组进行排序的时候,先将数组分割成更小的子数组,然后对子数组排序,最后排序后的子数组合并成一个完成的数组,在对子数组排序的时候可以使用相同的策略继续对子数组进行分割,直到子数组中只包含一个元素。
例如我们需要数组[3,2,6,4,8,1,7,5]排序,首先将数组分割成只包含单个元素的子数组:
[3] [2] [6] [4] [8] [1] [7] [5]
将相邻的两个子数组合并,得到包含两个元素的已排序子数组:
[2, 3] [4, 6] [1, 8] [5, 7]
继续两两合并:
[2, 3, 4, 6] [1, 5, 7, 8]
最终就可以得到一个完成的排序好的数组了:
[1, 2, 3, 4, 5, 6, 7, 8]
下面看一下怎么用JS代码实现一个归并排序。
首先看一下怎么合并两个已排序的子数组,代码如下:
/**
* 辅助方法,合并数组arr中的两个已排序的子数组
* 作为例子只考虑从小到大排序,其他排序可自定义比较函数,类似于Array#sort
* @param {*} arr 数组
* @param {*} start 起始位置
* @param {*} end 结束位置(包含在范围内)
* @param {*} mid 两个子数组的分割位置
*/
function merge(arr, start, end, mid) {
// 需要合并的元素个数
const count = end - start + 1;
// 左侧已排序数组
const left = arr.slice(start, mid + 1);
// 右侧已排序数组
const right = arr.slice(mid + 1, end + 1);
// 加入守卫元素,这样可以不用判断子数组是否为空
left.push(Infinity);
right.push(Infinity);
// 依次取出两个子数组中的较小的值
let i = 0;
let l = 0;
let r = 0;
while(i < count) {
if (left[l] < right[r]) {
arr[start + i] = left[l];
l++;
} else {
arr[start + i] = right[r];
r++;
}
i++;
}
}
可以把两个已排序的子数组看作是两堆扑克,每次从两队扑克中取出较小的一张牌,直到所有的牌取完,得到的就是一副排好序的扑克。
下面看一下如何使用递归实现归并排序:
首先计算出中心点将数组分割成两个子数组,对两个子数组分别排序,最后调用merge函数将两个已排序的子数组合并得到最终的排序数组。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。