JavaScript实现归并排序算法详解

news2024/10/7 15:25:56

JavaScript实现归并排序算法详解

说明

归并排序(Merge Sort)算法,也叫合并排序,是创建在归并操作上的一种有效的排序算法。算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。归并排序思路简单,速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列。

归并排序和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(n log n)的时间复杂度。代价是需要额外的内存空间。

归并排序是用分治思想,分治模式在每一层递归上有三个步骤:

分解(Divide):将n个元素分成个含n/2个元素的子序列。
解决(Conquer):用合并排序法对两个子序列递归的排序。
合并(Combine):合并两个已排序的子序列已得到排序结果。

实现过程

  1. 将所有数组项无限细分,得到1个个独立的单元,也就是不断分解。
  2. 将相近的两两进行比较,按照已排序数组合并,形成(n/2)个序列,每个序列包含2个数字。
  3. 将上述两个序列递归合并,按照已排序数组合并,形成(n/4)个序列,每个序列包含4个数字。
  4. 重复步骤2,直到所有元素合并排序完毕。

示意图

性能分析

平均时间复杂度:O(nlogn)
最佳时间复杂度:O(n)
最差时间复杂度:O(nlogn)
空间复杂度:O(n)
排序方式:In-place
稳定性:稳定

JS第1种写法,标准双指针移动比较

/**
 * 归并排序 ,采用分而治之(divide - conquer)的步骤
 * 1. 分解(Divide),把待排序元素的序列分解为两个子序列,以中间2分, 每个子序列包括一半成员。
 * 2. 解决(Conquer),对每个子序列分别调用归并操作, 进行递归或非递归循环操作,完成内部排序。
 * 3. 合并(Combine),合并两个排好序的子序列,生成排序结果。 归并排序的最坏时间复杂度和平均时间复杂度均为O(nlogn)
 */
(function () {
  // 将两个有序数组合并为一个新的有序数组
  function merge (arr, left, mid, right) {
    // 先建立一个长度等于原数组的临时数组
    const temp = []
    // 左侧指针
    let i = left
    // 右侧指针
    let j = mid + 1
    // 临时数组指针
    let k = 0
    // 当左指针小于中间,且右指针不大于最右侧时
    while (i <= mid && j <= right) {
      // 如果左侧小于右侧,将数移到临时数组中左侧
      if (arr[i] <= arr[j]) {
        temp[k++] = arr[i++]
        // 否则移动到临时数组右侧
      } else {
        temp[k++] = arr[j++]
      }
    }

    // 如果左边数组还有数据,就把左侧剩余都放入到原数组后面
    while (i <= mid) {
      temp[k++] = arr[i++]
    }
    // 如果右侧数组还有数据,把剩下的数据放入到原数组后面
    while (j <= right) {
      temp[k++] = arr[j++]
    }

    // 将排序后的元素全部移动到原数组中
    let x = 0
    while (left <= right) {
      arr[left++] = temp[x++]
    }
    console.log('arr:', arr)
  }

  function mergeSort (arr, left, right) {
    // 得到中间值
    const mid = Math.floor((left + right) / 2)
    // 如果左侧小于右侧则执行合并排序
    if (left < right) {
      // 递归合并左侧
      mergeSort(arr, left, mid)
      // 递归合并右侧
      mergeSort(arr, mid + 1, right)
      // 合并左右结果
      merge(arr, left, mid, right)
    }
    return arr
  }

  // test
  const arr = [7, 11, 9, 10, 12, 13, 8, -2, 0, 8]
  console.time('sort')
  console.log('origin:', arr)
  console.log('\r\nsorted:', mergeSort(arr, 0, arr.length - 1))
  console.timeEnd('sort')
})();

 JS第2种写法,双指针移动结合数组特性


(function () {
  function mergeSort (arr) {
    const len = arr.length
    if (len < 2) {
      return arr
    }
    // 取得当前数组的中间位置
    const mid = Math.floor(len / 2)
    const left = arr.slice(0, mid)
    const right = arr.slice(mid)
    console.log('mergeSort arr:', arr, left, right)
    // 递归调用,不断重复直到当前数组拆分剩1项
    return merge(mergeSort(left), mergeSort(right))
  }

  // 将两个有序数组进行合并为一个新的有序数组
  function merge (left, right) {
    // 建立一个空数组,用来存放排序结果
    const result = []
    // 左右数组的长度都不为空时,则将两个数组的第一个进行比较
    // 如左侧小于右,则移除左侧的内容到结果数据,反之移动右侧成员
    while (left.length && right.length) {
      if (left[0] <= right[0]) {
        result.push(left.shift())
      } else {
        result.push(right.shift())
      }
    }
    // 最后把剩余的左或者右侧成员全部添加到结果数组
    while (left.length) {
      result.push(left.shift())
    }

    while (right.length) {
      result.push(right.shift())
    }
    // 这样一趟下来后,两个数组就合并为一个新的排序数组
    return result
  }
})()

链接

归并排序算法源码:https://github.com/microwind/algorithms/tree/master/sorts/mergesort

其他排序算法源码:https://github.com/microwind/algorithms

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/726754.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Talk预告 | 南洋理工大学助理教授潘新钢:拖动你的GAN - 在生成图像流形上基于控制点的交互式图像编辑

本期为TechBeat人工智能社区第511期线上Talk&#xff01; 北京时间7月6日(周四)20:00&#xff0c;南洋理工大学 助理教授—潘新钢的Talk将准时在TechBeat人工智能社区开播&#xff01; 他与大家分享的主题是: “拖动你的GAN - 在生成图像流形上基于控制点的交互式图像编辑”&…

嵌入式_Keil (MDK - ARM) 的调试步骤

目录 1. 编译 调试 2. 复位 全速运行 3. 单步调试 4. 逐步调试 5. 跳出调试 6. 运行到光标处 7. 跳转到暂停行 8. 调试窗口 首先为什么需要在 MDK 中进行程序的调试呢&#xff1f; 在 MDK 中进行程序调试的主要目的是识别和解决程序中的问题和错误。 比如说找到程序中…

五种网络 I/O 模型

文章目录 1. 阻塞式 I/O 模型2. 非阻塞式 I/O 模型3. I/O 多路复用4. 信号驱动式 I/O5. 异步 I/O6. I/O 模型的分类 Unix 下有五种可用的 I/O 模型&#xff1a; 阻塞式 I/O 非阻塞式 I/O I/O 多路复用&#xff08;select/poll/epoll&#xff09; 信号驱动式 I/O&#xff08;…

【Spring MVC】Spring MVC程序开发教程:常见的注解及使用方式详情

前言 Spring MVC是一种常用的Web框架&#xff0c;它可以帮助开发人员快速构建可扩展的Web应用程序。为了提供更好的开发体验和更高的代码效率&#xff0c;Spring MVC提供了各种注解。这些注解可以用于控制器、请求参数、响应类型、表单数据验证、异常处理等方面。在本文中&…

卡尔曼滤波(附C++代码)

是什么 任何时候对于动态系统存在不确定信息&#xff0c;都可使用卡尔曼滤波&#xff08;Kalman Filter&#xff0c;下面简称为KF&#xff09;对系统下一步要做什么做出有根据的猜测。 KF对于连续变化的系统是理想的&#xff0c;优点是占用内存小而且速度快&#xff0c;非常适…

在Linux中安装RabbitMQ

RabbitMQ下载网址 Socat下载网址 erlang下载网址 RabbitMQ安装包依赖于Erlang语言包的支持&#xff0c;所以需要先安装Erlang语言包&#xff0c;再安装RabbitMQ安装包 通过Xftp软件将这三个压缩包上传到linux中的opt目录下 ,双击即可 在安装之前先查询…

Android oss policy上传

OSS Policy方式上传 一、 流程对比1.1 普通上传1.2 服务端签名后直传 二、获取上传的policy签名配置三、请求OSS上传文件四、调用应用服务器接口同步文件五、关于上传OSS报错注意事项六、附送链接 一、 流程对比 1.1 普通上传 缺点&#xff1a; 上传慢&#xff1a;用户数据需…

数学建模常用模型(五):多元回归模型

数学建模常用模型&#xff08;五&#xff09;&#xff1a;多元回归模型 由于客观事物内部规律的复杂性及人们认识程度的限制&#xff0c;无法分析实际对象内在的因果关系&#xff0c;建立合乎机理规律的数学模型。所以在遇到有些无法用机理分析建立数学模型的时候&#xff0c;…

docker中运行RabbitMq的启用插件指南

我们使用 Docker 来运行 RabbitMQ&#xff0c;有时需要启用一些插件&#xff0c;这个与正常安装的启用插件的步骤会有所不同。以下是在 Docker 中启用 RabbitMQ 插件的一般步骤&#xff1a; 首先&#xff0c;确认已经将 rabbitmq_delayed_message_exchange-3.12.0.ez 插件文件复…

raid5两块磁盘掉线导致阵列崩溃的服务器数据恢复案例

服务器数据恢复环境&#xff1a; DELL PowerVault系列某型号存储&#xff0c;15块硬盘搭建了一组RAID5磁盘阵列。 服务器故障&检测&#xff1a; 存储设备raid5阵列中一块磁盘由于未知原因离线&#xff0c;管理员对该磁盘阵列进行了同步操作。在同步的过程中又有一块磁盘指示…

使用 hbuilderx 配置 MuMu模拟器进行调试

第一步 先安装MuMu模拟器&#xff0c;调成手机模式。 第二步 查看MuMu模拟器监听的端口。 在安装目录下 /vms/MuMuPlayer-12.0-0/MuMuPlayer-12.0-0 旧端口7555&#xff0c;新端口号16384 切换到安装目录下的 /shell&#xff0c;然后shift右击&#xff0c;打开 powershell&a…

【服务器数据恢复】raid5崩溃的redhat linux系统数据恢复案例

服务器数据恢复环境&#xff1a; 一台ibm某型号服务器&#xff0c;5块硬盘组建一组raid5磁盘阵列&#xff0c;redhat linux操作系统&#xff0c;上层部署有oracle数据库。 服务器故障&#xff1a; raid5阵列中两块硬盘离线&#xff0c;服务器崩溃。经过初检发现故障服务器中的…

基于SpringBoot的医护人员排班系统【附开题(bao告)和万字文档(Lun文)和搭建文档】

主要功能 前台登录&#xff1a; ①首页&#xff1a;医院信息展示、医护信息展示、排班信息展示、投诉信息展示 ②医院信息&#xff1a;名称查询、医院查看、医院简介、可以点赞、可以评论、点我收藏 ③医护信息&#xff1a;根据工号、姓名查询、点击查看医护信息、可以收藏 ④…

Simulink仿真模块 - Band-Limited White Noise

Band-Limited White Noise模块的功能是在连续系统中引入白噪声。它所在的库为: Simulink / Sources 如图所示: Band-Limited White Noise 模块生成适合在连续系统或混合系统中使用的正态分布随机数。 白噪声仿真 从理论上讲,连续白噪声的相关时间为 0,功率谱密度 …

飞利浦的护眼台灯好用吗?南卡/飞利浦/雷士对比测评,看看哪款更好用!

日常生活中&#xff0c;灯光对于我们重要性不用多说。不管是学习还是办公等环境都需要合适的光线&#xff0c;而台灯作为补充光线小型家电&#xff0c;基本每个家庭里都会备着一台&#xff0c;特别是对于长期使用电脑的上班族或者需要长时间学习的学生这类人员。但是台灯的种类…

【大数据技术】hive 窗口函数sum range between的详细介绍

【大数据技术】hive 窗口函数sum range between的详细介绍 数据准备 建表 create table range_test( name string, month int , sales int ) row format delimited fields terminated by "," ;插入数据 load data local inpath "/home/xx/test/1.t…

双击就能运行的Win95,流畅稳定还内置大型游戏

像咱这样的新时代互联网民工&#xff0c;上班面对 Win10/11 下班也还是一样&#xff0c;难免有时候觉得腻。 回味起当初的 Win7、Win8、Win XP &#xff0c;不管当初受过什么伤&#xff0c;现在只有美好的回忆。 大家可能还想象过&#xff0c;用现在配置去运行老系统。 不知高…

uniapp 小程序 vue TypeError: Cannot read property ‘toString‘ of undefined

是因为对字符串使用toString的时候页面中的数据还没有加载 。错误代码&#xff1a; 可以使用 v-if 修改为&#xff1a;

AR是现实的商业创新,还是虚幻的电子梦境?

点击文末“阅读原文”即可参与节目互动 剪辑、音频 / 卷圈 运营 / SandLiu 卷圈 监制 / 姝琦 封面 / 姝琦Midjourney 产品统筹 / bobo 在本期节目中&#xff0c;我们将深入探讨AVAR的创始人胡雅婷的创业故事。 我们从年轻人偏爱虚拟偶像和热衷元宇宙创业的社会话题出发&…

递归的深层次理解+初始搜索算法

1)什么是递归:就是函数自己调用自己的过程 2)为什么会使用到递归:主问题->相同的子问题&#xff0c;相同的子问题->一样相同的子问题 3)递归结束的条件:也就是细节和出口最小的不能在继续进行分割的子问题 4)宏观看待递归的过程: 1)不要在意递归展开的细节图 2)那递归的函…