做者:Abhilash Kakumanu翻译:疯狂的技术宅javascript
原文:https://stackabuse.com/merge-...前端
未经容许严禁转载java
在本文中,咱们学习 Merge Sort 背后的逻辑,并用 JavaScript 实现。最后,在空间和时间复杂度方面将归并排序与其余算法进行比较。程序员
归并排序使用分而治之的概念对给定的元素列表进行排序。它将问题分解为较小的子问题,直到它们变得足够简单以致能够直接解决为止。面试
如下是归并排序的步骤:算法
以数组 [4, 8, 7, 2, 11, 1, 3]
为例,让咱们看一下归并排序是如何工做的:segmentfault
首先实现一个将两个已排序子数组合并为一个已排序数组的函数 merge()
。要注意着两个子数组是已经被排好序的,这一点很是重要, 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 ] }
在这个函数中,经过把两个排好序的子数组(left
、right
)合并来得到一个排好序的大数组。首先,建立一个空数组。以后在 left
和 right
两个子数组中最小元素中的较小的一个,并将其添加到空数组。咱们只须要检查 left
和 right
子数组中的第一个元素,由于它们是已排好序的。微信
在这个过程当中,从子数组中删除了被选择的元素(经过 shift()
函数实现)。继续这个过程,直到其中一个子数组变为空。最后把非空子数组的剩余元素(由于它们已经被排序)插入主数组的最后面。
如今有了合并两个已排序数组的代码,接下来为实现归并排序算法的最终代码。这意味着要继续分割数组,直到最终只包含一个元素的数组为止:
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)) }
在代码中先肯定中点,并用 splice()
函数将数组分为两个子数组。若是元素数量为奇数,则左侧的元素数量会少一个。不断的划分数组,直到剩下单个元素的数组(array.length < 2
)。而后用以前实现的 merge()
函数合并子数组。
代码实现后用前面的用例测试一下:
array = [4, 8, 7, 2, 11, 1, 3]; console.log(mergeSort(array));
输出符合预期:
1,2,3,4,7,8,11
归并排序的最差时间复杂度为 $O(n\\log n)$,与快速排序的最佳情时间复杂度相同。归并排序是目前最快的排序算法之一。
与快速排序不一样,归并排序不是in-place排序算法,这意味着除了输入数组以外,它还会占用额外的空间。这是由于咱们使用了辅助数组来存储子数组。归并排序的空间复杂度为 $O(n)$。
归并排序的另外一个优势是很是适合多线程,由于每一个被划分出的一半均可以单独排序。另外一种常见的减小归并排序运行时间的方法是在到达相对较小的子数组时(大约 7 个元素)使用插入排序。这是由于插入排序在处理小型或几乎排好序的数组时表现很是好。
在本文中,咱们了解了Merge Sort算法背后的逻辑,并用 JavaScript 实现。它是基本排序算法之一,能够帮助咱们更好的了解分治法策略。