JS 二路归并排序(分治排序)

703 阅读1分钟

二路归并排序定义和原理:

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题(divide)成一些小的问题然后递归求解,而治(conquer) 的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

image.png

二路归并的分解图形数据结构非常相似二叉树结构,一般采用递归方法进行。

解析:

第一步: 分

即将数组分解成一个一个最小单元,每次分解取中间元素作为分解点,如图:

ScreenRecorderProject6.gif

每一层切割都是在切割数组之后的结果接续切割,采用递归分解,当切割的数组还剩一个元素的时候,跳出递归

const sliceArray = function(arr) {
    if (arr.length < 2) {
        return arr
    }
   let mid = Math.floor(arr.length  / 2)
   let left = sliceArray(arr.slice(0, mid))
   let right = sliceArray(arr.slice(mid, arr.length))  
}

在切割过后,都有一次合并操作,即为治。

第二步: 治

治主要是合并数组的操作,在合并的同时进行排序。如图:

ScreenRecorderProject7.gif

合并操作的主要思想:

开辟一个新的数组空间,设定双指针分别指向数组的开始,依次比较大小,push 进新的数组中,并控制指针的移动,当指针移动到最后,即可拼接未完成数组后面的元素(切割后的数组也是经过合并的,也就是说数组本身是排序的,当一侧指针走完后,另一侧可直接拼接在结果后面)

图解:

ScreenRecorderProject1_1.gif

合并操作代码:

const mergin = function (l1, l2) {
    let temp = []
    while(l1.length && l2.length) {
        const n1 = l1.shift()
        const n2 = l2.shift()
        if (n1 > n2) {
            temp.push(n2)
            l1.unshift(n1)
        } else {
            temp.push(n1)
            l2.unshift(n2)
        }
    }
    return [...temp, ...l1, ...l2]
}

完整代码:

/**
 * @param {number[]} nums
 * @return {number[]}
 */

const mergin = function (l1, l2) {
    let temp = []
    while(l1.length && l2.length) {
        const n1 = l1.shift()
        const n2 = l2.shift()
        if (n1 > n2) {
            temp.push(n2)
            l1.unshift(n1)
        } else {
            temp.push(n1)
            l2.unshift(n2)
        }
    }
    return [...temp, ...l1, ...l2]
}

const sliceArray = function(arr) {
    if (arr.length < 2) {
        return arr
    }
   let mid = Math.floor(arr.length  / 2)
   let left = sliceArray(arr.slice(0, mid))
   let right = sliceArray(arr.slice(mid, arr.length))
  return mergin(left, right)
   
}

var sortArray = function(nums) {
   return sliceArray(nums)
};