疯狂的技术宅

以前出于工作目的,编写和翻译了大量的技术文章,以前端为主,删掉了过时的、毫无营养的内容,留下的都是精华。


  • 首页

  • 分类

  • 标签

  • 归档

  • 关于本站

  • 回到主站

  • 搜索

用 JavaScript 实现归并排序

时间: 2020-10-20 分类: 数据结构与算法   字数: 1216 字 阅读: 3分钟
标签: #归并排序# #算法# #JavaScript#
  • 本文译自:https://stackabuse.com/merge-sort-in-javascript/
  • 译者:疯狂的技术宅

在本文中,我们学习 Merge Sort 背后的逻辑,并用 JavaScript 实现。最后,在空间和时间复杂度方面将归并排序与其他算法进行比较。

归并排序背后的逻辑

归并排序使用分而治之的概念对给定的元素列表进行排序。它将问题分解为较小的子问题,直到它们变得足够简单以至可以直接解决为止。

以下是归并排序的步骤:

  1. 将给定的列表分为两半(如果列表中的元素数为奇数,则使其大致相等)。
  2. 以相同的方式继续划分子数组,直到只剩下单个元素数组。
  3. 从单个元素数组开始,合并子数组,以便对每个合并的子数组进行排序。
  4. 重复第 3 步单元,直到最后得到一个排好序的数组。

以数组 [4, 8, 7, 2, 11, 1, 3] 为例,让我们看一下归并排序是如何工作的:

归并排序

用 JavaScript 实现归并排序

首先实现一个将两个已排序子数组合并为一个已排序数组的函数 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 实现。它是基本排序算法之一,可以帮助我们更好的了解分治法策略。

标签: #归并排序# #算法# #JavaScript#

标题:用 JavaScript 实现归并排序

链接:https://fe-tech.viewnode.com/post/202010/20/

作者:疯狂的技术宅

声明: 本博客文章除特别声明外,均采用 CC BY-NC-ND 4.0 国际许可协议( 知识共享署名-非商业性使用-禁止演绎 4.0),转载请注明出处!

浅析script 标签的 async 和 defer 属性
在 Vue.js 中集成 CSS 框架
  • 文章目录
  • 站点概览
疯狂的技术宅

疯狂的技术宅

退休程序员,硬件发烧友,人工智能爱好者。写写代码喝喝茶,晒晒太阳带带娃。

457 日志
8 分类
583 标签
GitHub
友情链接
  • viewnode
  • mofish
标签云
  • Javascript 172
  • Node.Js 62
  • Vue 36
  • Typescript 28
  • 实战项目 28
  • 面试 21
  • React 20
  • Css 17
  • 面试题 16
  • 教程 13
  • Promise 12
  • Chrome 9
  • Debug 9
  • 调试 9
  • 资源 9
  • Deno 8
  • Dom 8
  • 杂谈 8
  • 正则表达式 8
  • 测试 8
  • 归并排序背后的逻辑
  • 用 JavaScript 实现归并排序
  • 归并排序的效率
  • 总结
© 2018 - 2022 疯狂的技术宅 All Rights Reserved
Powered by - Hugo v0.99.0 / Theme by - NexT
Storage by 俺的服务器 / 冀ICP备2022010157号
0%