归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:
- 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法);
- 自下而上的迭代;
在《数据结构与算法 JavaScript 描述》中,作者给出了自下而上的迭代方法。但是对于递归法,作者却认为:
However, it is not possible to do so in JavaScript, as the recursion goes too deep for the language to handle.
然而,在 JavaScript 中这种方式不太可行,因为这个算法的递归深度对它来讲太深了。
和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是 O(nlogn) 的时间复杂度。代价是需要额外的内存空间。
2. 算法步骤
归并排序使用分而治之的概念对给定的元素列表进行排序。它将问题分解为较小的子问题,直到它们变得足够简单以至可以直接解决为止。
以下是归并排序的步骤:
- 将给定的列表分为两半(如果列表中的元素数为奇数,则使其大致相等)。
- 以相同的方式继续划分子数组,直到只剩下单个元素数组。
- 从单个元素数组开始,合并子数组,以便对每个合并的子数组进行排序。
- 重复第 3 步单元,直到最后得到一个排好序的数组。
3. 动图演示
代码实现
将两个已排序子数组合并为一个已排序数组的函数?merge()
function merge(left, right) {
let arr = []
// 如果任何一个数组为空,就退出循环
while (left.length && right.length) {
// 从左右子数组的最小元素中选择较小的元素
if (left[0] < right[0]) {
arr.push(left.shift())
} else {
arr.push(right.shift())
}
}
// 连接剩余的元素,防止没有把两个数组遍历完整
return [ ...arr, ...left, ...right ]
}
更完整的实现
function mergeSort(array) {
const half = array.length / 2
if(array.length < 2){
return array
}
const left = array.splice(0, half)
return merge(mergeSort(left),mergeSort(array))
}
|