排序算法-归并排序

200 阅读3分钟

「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战

归并排序

介绍

归并排序 它是基于 归并操作,来进行的排序算法。采用的是 分治法 的一个思想。

大白话就是:将数据 根据某种方式 先 散开,再根据某种方式 进行 并,来得到我们想要的排序结果。

  • 分开 的操作,我们使用到了,二分的方式。

  • 合并 的操作,类似于数据结构中的 双指针算法 中的 快慢指针。可以看下对应的 数据结构-双指针算法 这篇文章

动图演示

mergeSort.gif

步骤详解

给定数据为 const arr = [15, 5, 25, 20, 30, 10, 35]

  • 先进行 归并排序 中 分 的操作

    每次获取单个数据里面的中间下标,然后通过数组的 slice 方法,进行分割数组,之后 递归 操作,直到单个数组里的长度为 1,即可结束 递归 操作。

    代码为:

      
      // 找到中间下标
      const mid = Math.floor(data.length / 2)
      
      // 分割
      const left = data.slice(0, mid)
      const right = data.slice(mid)
      
      // 递归
      return mergeSort(left), mergeSort(right)
    

    image.png

    此时 分 的操作进行完毕,得到的是一排单个的数组为:[15],[5],[25],[20],[30],[10],[35]

  • 通过上面的步骤,我们得到 分 的结果后,接下来进行 合 的操作,通过 类似与 快慢指针 一样。

    该操作我们需要创建一个空的数组 const temp = []

    然后循环判断 leftright 数组是否还有值,直到其中一个数组值为空,结束循环。循环体的内容为:

    • 每次取出 leftright 里面的第一个值进行比较

    • 将小的值,先进行 shift 弹出

    • pushtemp 数组中

    最后进行连接操作 temp.concat(left, right),即可得到从小到大的排序数组。

    image.png

  • 这里讲解下最后一步 合 的步骤

    此时可以看到

    • left = [5,15,25]
    • right = [10,20,30,35]

    将 左指针 放置在 left 下的第 0 个下标处, 并且 右指针 放置在 right 下的第 0 个下标处。

    image.png

    • 第一次比较:

      因为 左指针 对应的值 小于 右指针 对应的值,所以 左指针 下标进行 ++ 操作

      image.png

    • 第二次比较

      此时 左指针 对应的值 大于 右指针 对应的值,所以 右指针 下标进行 ++ 操作

      image.png

    依次类推...

    • 最后一次

      image.png

      可以看到最后一次的比较中 左指针 下标已经超出数组最大长度,也就是该 left 数组里面的值已经全部比较完毕。

      所以最后将 right 剩余的值,直接连接 temp 数组中,放入即可。

完整代码

    const merge = (left, right) => {
      const temp = []
      while (left.length && right.length) {
        if (left[0] < right[0]) {
          temp.push(left.shift())
        } else {
          temp.push(right.shift())
        }
      }
      // 因为上面的弹出操作,所以留下了最大的值,直接将 temp 和 最大值进行连接即可
      return temp.concat(left, right)
    }
    const mergeSort = (data) => {
      if (data.length <= 1) {
        return data
      }
      const mid = Math.floor(data.length / 2)
      const left = data.slice(0, mid)
      const right = data.slice(mid)

      return merge(mergeSort(left), mergeSort(right))
    }

总结

归并排序 是一种稳定的排序方式,且 比较次数 是所有排序中最少的。

缺点也很明显,需要开辟新的内存空间。数据量越大,就会导致此排序方式占用内存越多。