• 排序算法-(6)归并排序


    归并排序

    归并算法应用到分治策略,简单说就是把一个答问题分解成易于解决的小问题后一个个解决,最后在把小问题的一步步合并成总问题的解。归并排序应用递归来把数组分解成一个个小数组,直到小数组的数位有序,在把有序的小数组两两合并而成有序的大数组。

    最差、最优、平均时间复杂度都为O(nlogn)。辅助空间O(n)。稳定性:稳定。

    算法实现

    function merge(left,right){
        let tmp=[];
        while(left.length&&right.length){//合并左右数组
            if(left[0]<right[0])
                tmp.push(left.shift());
            else
                tmp.push(right.shift());
        }
        return tmp.concat(left,right);
    }
    function mergeSort(a){
        if(a.length==1)//终止条件
            return a;
        let mid=a.length>>1,
            left=a.slice(0,mid),
            right=a.slice(mid);
        return merge(mergeSort(left),mergeSort(right))
    }

    这段合并排序的代码相当简单直观,但是mergeSort()函数会导致很频繁的自调用。一个长度为n的数组最终会调用mergeSort() 2*n-1次,这意味着如果需要排序的数组长度很大会在某些栈小的浏览器上发生栈溢出错误。

    这里插个话题,关于递归调用时浏览器的栈大小限制,可以用代码去测试

    var cnt = 0;
    try {
      (function() {
        cnt++;
        arguments.callee();
      })();
    } catch(e) {
      console.log(e.message, cnt);
    }
    
    
    // chrome: Maximum call stack size exceeded 35992
    // firefox: too much recursion 11953

    遇到栈溢出错误并不一定要修改整个算法,只是表明递归不是最好的实现方式。这个合并排序算法同样可以迭代实现,比如(摘抄自《高性能JavaScript》):

    function merge(left, right) {
        let result = [];
        while (left.length && right.length) {
            if (left[0] < right[0])
                result.push(left.shift());
            else
                result.push(right.shift());
        }
        return result.concat(left, right);
    }
    function mergeSort(a) {
        if (a.length === 1)
            return a;
        let work = [],len=a.length;
        for (let i = 0; i < len; i++)
            work.push([a[i]]);
        work.push([]); // 如果数组长度为奇数
        let last=0;
        for (let lim = len; lim > 1; lim = (lim + 1)>>1) {
            for (let j = 0, k = 0; k < lim; j++, k += 2) {
                work[j] = merge(work[k], work[k + 1]);
                last=j;
            }
            work[last+1] = []; // 如果数组长度为奇数
        }
        return work[0];
    }

    这个版本的mergeSort()函数功能与前例相同却没有使用递归。尽管迭代版本的合并排序算法比递归实现要慢一些,但它并不会像递归版本那样受调用栈限制的影响。把递归算法改用迭代实现是实现栈溢出错误的方法之一。

  • 相关阅读:
    Python中pymssql 的使用操作
    Python连接mysql数据库及简单增删改查操作示例代码
    Python之模块和包的创建与使用
    SQL SERVER将多行数据合并成一行
    SQL Server根据子查询更新语句update
    在VMware虚拟机中安装windows server2016步骤详解(带图解)
    http请求错误合集
    第三方图标库(三)iconMoon
    第三方图标库学习(二)Font Awesome
    MapperScannerConfigurer的原理
  • 原文地址:https://www.cnblogs.com/wuguanglin/p/mergeSort.html
Copyright © 2020-2023  润新知