1

假设有这样一个需求,一个数组的子元素全是有序数组,类似:

let arr= [[1, 2], [0, 3, 4,4,4,6,7,8,9,10], [-1, 4],[-1,3],[-1],[100,200],[5,1000,30000]];

我们希望将上述数组合并为一个有序数组,怎么处理呢?

最简单的方案就是:
将数组整体合并,然后sort排序,代码如下:

let ret=arr.reduce((arr1,arr2)=>arr1.concat(arr2)).sort((a,b)=>a-b);
ret=Array.from(new Set(ret));
console.log(ret);

但是上面的代码没有充分利用数组子元素本身就是有序数组这一特性,我们利用“归并排序”算法,可以大大的提高类似数组的合并排序性能,代码(代码里面有详细注释)如下:

let arr= [[1, 2], [0, 3, 4,4,4,6,7,8,9,10], [-1, 4],[-1,3],[-1],[100,200],[5,1000,30000]];
// let arr= [[1,2,3]];

function merge(arr){

    //记录每一个数组循环比较时的下标变化
    function filterIndexArr() {
        indexArr=indexArr.filter((item,index)=>{
            return item.count<arr[item.index].length;
        });
    }

    //将每次比较的元素放进一个临时数组里面,取出最小值放入ret
    function pushToArr(arr) {
        let minVal=arr[0].val;
        let increaseArr=[arr[0].index];
        arr.forEach((item,index)=>{
            if (minVal>item.val){
                minVal=item.val;
                increaseArr=[item.index];
            }else if (minVal==item.val && index!=0){
                increaseArr.push(item.index)
            }
        });
        increaseArr.forEach((item)=>{
            let thatItem=item;
            indexArr.forEach((item)=>{
                if (item.index==thatItem){
                    item.count++;
                }
            });
        });
        filterIndexArr();
        ret.push(minVal);
    }

    let ret=[];
    let indexArr=arr.map((item,index)=>{
        return {
            index,
            count:0
        }
    });
    filterIndexArr();

    let compareArr=[];
    while (indexArr.length>1){
        //循环比较每个数组的第一个元素
        compareArr=indexArr.map((item,index)=>{
            return {
                index:item.index,
                val:arr[item.index][item.count]
            }
        });
        pushToArr(compareArr);
    }
    //取出最后不需要比较的数组元素,直接拼接到ret后面
    let remainArr=arr[indexArr[0].index].slice(indexArr[0].count);
    ret=ret.concat(remainArr);
    ret=Array.from(new Set(ret));
    return ret;
}

let ret=merge(arr);
console.log(ret);

由于子数组本身有序,分别记录要被比较数组的下标,循环取出最小值push到ret就可以了,是不是很简单。


安静的木马
957 声望11 粉丝