javascript 归并(递归+非递归)

递归

function ArrayList(){
 
    var array = [];
 
    this.insert = function(item){
        array.push(item);
    };
 
    this.toString= function(){
        return array.join();
    };

    this.mergeSort = function(){    //this.mergeSort = function(array)是不行的,不知道为什么
        array = mergeSortRec(array);
    }

    function mergeSortRec(array){
        if(array.length > 1){
            // const { length } = array; //可以
            const length = array.length;
            const middle = Math.floor(length/2);
            const left = mergeSortRec(array.slice(0, middle));
            const right = mergeSortRec(array.slice(middle, length));
            array = merge(left, right);
        }
        return array;
    };

    function merge(left, right){
        let i = 0;
        let j = 0;
        const result = [];
        while(i < left.length && j < right.length){
            result.push(left[i] - right[j] < 0 ? left[i++] : right[j++]);
        }
        return result.concat(i < left.length ? left.slice(i) : right.slice(j));
    }
 
}
 
 
console.log('********** Merge Sort **********');
 var array = new ArrayList();
 
array.insert(3);
array.insert(1);
array.insert(4);
array.insert(5);
array.insert(0);
array.insert(2);
array.insert(9);
array.insert(8);
array.insert(7);
array.insert(6);
 
console.log(array.toString());
 
array.mergeSort();
 
console.log(array.toString());

整理了一下方便背

function mergeSort(array){
	if(array.length > 1){
		// const { length } = array; //可以
    	const length = array.length;    
		const middle = Math.floor(length/2);
    	const left = mergeSort(array.slice(0, middle));
   		const right = mergeSort(array.slice(middle, length));
    	array = merge(left, right);
    }
    return array;
};
 
function merge(left, right){
    let i = 0;
    let j = 0;
    const result = [];
    while(i < left.length && j < right.length){
            result.push(left[i] - right[j] < 0 ? left[i++] : right[j++]);
    }
    return result.concat(i < left.length ? left.slice(i) : right.slice(j));
}

 
console.log('********** Merge Sort **********');
var array = [3,1,4,5,0,2,9,8,7,6];
 
console.log(array.toString());
 
mergeSort(array);//没有返回的东西  (为什么???
console.log(array);//[3,1,4,5,0,2,9,8,7,6]
console.log(mergeSort(array).toString());//0,1,2,3,4,5,6,7,8,9

 

非递归

不简单,但懂了之后会觉得很厉害

贴一个讲解视频,这是用c实现的。首先了解大概的思路https://www.icourse163.org/learn/ZJU-93001?tid=1003997005#/learn/content?type=detail&id=1007588513&cid=1009165143&replay=true

我想用上面的思路实现代码,但是暂时实现不了。

贴一个代码实现(来源:https://www.bbsmax.com/A/1O5Ewegnz7/

/*
     *
     * 非递归版归并排序,思路如下:
     * 至底而上的思路,二和一,四和一,最后是一半一半和整。
     * 循环从左到右依次执行,为了节省空间,我节省了右序列,将原数列的一部分作为右小序列,这一部分不会被覆盖。
     * 作者:吴伟欣
     * */
    function mergeSearch(arr)
    {
        var len = arr.length;
        var left_s,left_e,right_s,right_e;
        var left_list = null;   //只需要一半即可,节省空间,因为原数组后半段是不可能被覆盖的。
        for (var i = 1;i<len;i*=2)
        {
            var next = 0;//每一次合并以后初始化next
            for(left_s=0;left_s<len;left_s=right_e)
            {
                next = left_s;
                left_e = right_s = left_s + i;
                right_e = right_s + i;
                if(right_e > len)
                {
                    right_e = len;
                }
                //复制左边的数组
                left_list = arr.slice(left_s,left_e);
                var left_index = 0;
                var left_len = left_list.length;//空间换取时间
                while(left_index<left_len)       //归并代码
                {
                    if((right_s>=right_e)||(left_list[left_index]<=arr[right_s])) //短路逻辑,优化性能
                    {
                        arr[next++] = left_list[left_index++];
                    }else
                    {
                        arr[next++] = arr[right_s++];
                    }
                }
            }
        }
    }
    //测试代码
    var a = [3,7,1,2,10,9,1,6];
    var b = [10,9,8,2,7,10,10,10,9,9,9,8];
    mergeSearch(a);
    mergeSearch(b);
    alert(a);
    alert(b);

(作者原话)首先,归并思路应该不难写。我的思路是这样的,先整体思维是,很自然的从单个合并,然后在合并,最后合成一个整体。每次都是两两合并。细节方面是,合并的时候到底怎么做比较好呢,可以想象,我们可以创建一个整数列,然后合并的时候放进去,整条合并完,在给原来的,这当然是很笨的方式。我采用的是,每两个需要合并的子序列肯定是不可以在原数列的空间上进行排序,但是至少需要多少空间呢,你会发现,这两个序列的右边那个是不可能被覆盖,那意味着,这两个序列的右边序列是可以在原数列上玩,左序列我会每次创建空间,然后放进原数列。短路逻辑那里,是考虑到如果左边序列完全排序好了,那么右序列默认是在原序列上,并且排好序,所以很明显已经搞定,后面的是不需要在动了,直接进入下一个序列合并。整体最坏复杂度,应该是这样的,一个logn 和一个n循环,整体应该是nlogn

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值