【拿下JS算法】:归并排序

一、概念

  • “归并”:将两个已经排序的序列合并成一个序列的操作。
  • “归并排序”:创建在归并操作上的一种有效的排序算法,1945年由约翰·冯·诺伊曼首次提出。该算法是采用“分治法”的一个非常典型的应用,且各层分治递归可以同时进行。
  • “分治法”:“分而治之”,把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。
    • 分割:递归地把当前序列平均分割成两半
    • 集成:在保持元素顺序的同时将上一步得到的子序列集成到一起(归并)

二、特点

稳定、高效(速度仅次于快速排序)、消耗空间。

三、思想梳理

现在有数组[12, 2 , 13, 23, 4, 45], 分步骤执行

  • 第一步:
    将原序列分割成长度为n的子序列
    [12] [2] [13] [23] [4] [45]
  • 第二步:
    每两个子序列进行对比,将结果放入一个新序列
    [12] [2] [13] [23] [4] [45]
    [2 , 12] [13, 23] [4, 45]
  • 第三步
    将第二步中新的序列再进行两两对比,重复此环节,得到最终结果
    [2 , 12] [13, 23] [4, 45]
    [2, 12, 13 23] [4, 45]
    [2, 4, 12, 13, 23, 45]

四、代码逻辑

  • 将此序列均分成两个长度为n/2的子序列
  • 再将每个子序列均分成两个m/2个子序列,直到长度为1
  • 将两个排序好的子序列合并成一个新序列,得到最终序列

五、代码实现

function mergeSort(arr) {
    // 序列长度为1时退出
    if (arr.length < 2 ) {
        return arr
    }

    // 将序列分为两个子序列,这一块起到“分治法”中的“分割”
    const middle = Math.floor(arr.length/2)
    const left = arr.slice(0, middle)
    const right = arr.slice(middle)
    
    // 递归,这一块起到“分治法”中的“集成”
    return merge(mergeSort(left), mergeSort(right))
}

function merge(left, right) {
    const result = []
    
    // 两个子序列进行比较,从小到大放入新的序列result中
    while(left.length > 0 && right.length > 0) {
        // 将较小的放入result,并改变left或者right的长度,灵活使用shift方法
        if (left[0] < right[0]) {
            result.push(left.shift())
        } else {
            result.push(right.shift())
        }
    }
    
    // 先将小的元素放入result中,直到left或者right为空,剩余的一个数组肯定是大于result的有序序列,所以直接通过concat进行合并返回
    return result.concat(left, right)
}

// 测试
const arr = [12, 2 , 13, 23, 4, 45]
mergeSort(arr) // [2, 4, 12, 13, 23, 45]
原文地址:https://www.cnblogs.com/huiwenhua/p/13633199.html