归并算法迭代版本的探索(Javascript 版)

众所周知,归并算法主要有两种方法实现,递归、迭代(插一句,一般递归都可用迭代实现),且时间复杂度都是O(nlog(n)),递归网上版本较多,简单提一嘴,主要是讲解迭代的 JS 实现

归并算法思路

  • 看一张《学习JavaScript数据结构与算法(第3版)》的图就一目了然了,先将数组拆分为小数组,再排序并合并回去,一看到此图自然就会联想到递归方法了,这正是递归调用栈的步骤展示

请添加图片描述

递归版

  • 优缺点:递归一般优点是代码量少,缺点是较抽象、调用栈较大
  • 思路:通过递归去拆分数组,通过merge函数去合并子数组
var sortArray = function (nums) {
    if (nums.length < 2) return nums
    let mid = Math.floor(nums.length / 2)
    let left = nums.slice(0, mid), right = nums.slice(mid)
    // 合并两个数组
    let merge = (l, r) => {
        let res = []
        while (l.length && r.length) {
            l[0] < r[0] ? res.push(l.shift()) : res.push(r.shift())
        }
        return [...res, ...l, ...r]
    }
    return merge(sortArray(left), sortArray(right))
}

迭代版

  • 优缺点:据网上结论是效率会高很多,但在力扣实测并不如意。是用的第912题“排序数组”,顺便还测了冒泡排序和快速排序,结果一目了然。归并排序迭代法的效率反而降低了,当然,也许是使用的场景不对

请添加图片描述

  • 思路:通过循环直接去找到子数组,合并,继续找,继续合并…合并完当前子数组后继续合并得到的大数组,如此反复下去,直接看代码比较抽象,先模拟下迭代过程
原数组:[8,7,6,5,4,3,2,1]
循环1,步长为2^0,子数组长度为1,将两个~合并成一个长度为2的大~:
       [[8,7],6,5,4,3,2,1] -> [[7,8],6,5,4,3,2,1]
       [7,8,[6,5],4,3,2,1] -> [7,8,[5,6],4,3,2,1]
       ... -> [7,8,5,6,3,4,1,2]
循环2,步长为2^1:
       [[7,8,5,6],3,4,1,2] -> [[5,6,7,8],3,4,1,2]
       [5,6,7,8,[3,4,1,2]] -> [5,6,7,8,[1,2,3,4]]
循环3,步长为2^2:
       [5,6,7,8,1,2,3,4] -> [1,2,3,4,5,6,7,8]
  • 代码
var sortArray = function (nums) {
 	 // 合并两个数组,用了许多API简化书写,和递归的合并同理,但需要额外处理
	 merge = (arr, left, center, right) => {
        let res = []
        let l = arr.slice(left, center)
        let r = arr.slice(center, right + 1)
        while (l.length && r.length) {
            l[0] < r[0] ? res.push(l.shift()) : res.push(r.shift())
        }
        res.push(...l, ...r)
        for (let i = left; i <= right; i++) {
            arr[i] = res[i - left]
        }
        return arr
    }
    // 双循环,找到子数组
    for (let step = 1; step < nums.length; step *= 2) {
        let offset = step * 2;
        for (let start = 0; start < nums.length; start += offset) {
        	// 与边界比较,不得长于数组长度
            nums = merge(nums, start,
                Math.min(nums.length - 1, start + step),
                Math.min(nums.length - 1, start + offset - 1))
        }
    }
    return nums
}

如果觉得对你有帮助的话,点个赞呗~

反正发文又不赚钱,交个朋友呗~

如需转载,请注明出处foolBirdd

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值