您的位置:首页 > Web前端 > JavaScript

归并算法的JS实现及分析(分治,递归,归并)

2017-10-20 02:03 573 查看

有趣的扑克牌排序帮助你理解归并算法

思考一下有趣的扑克牌排序,比如你的面前有两堆(A堆和B堆)牌,牌面朝上,你每次比较两堆牌最顶上的两张牌,选择较小的一张,放在另一个堆(C堆),重复此过程,直到A堆和B堆的牌耗尽。这个过程就是归并。但此时你得到的C堆的牌可能不是升序的。因为你的A堆或B堆可能不是升序的。想象下你的A堆有5,3,………,B堆有12,1,…………。这时你得到的C堆就会是5,3,………..。其中的原因就是我刚刚说的A堆或B堆可能不是升序的。但是如果将A堆进行拆分为A1和A2,再将A1拆分为A11和A12,A2拆分为A21和A22,然后继续往下拆,直到,拆到两边各剩一张牌。这个过程就是分治(分治分治分开治理嘛)。这个时候再对两边各剩一张牌进行归并,得到一定是一个升序的两张牌。将所有的两边各一张牌进行归并,得到许多升序的两张牌,再将两边都为升序的两张牌进行归并,就会得到升序的四张牌。以此类推,就会归并得到升序的A堆和B堆,也就解决了刚刚A堆或B堆可能不是升序的问题。不断的归并又可以用递归来解决。

所以,分治,递归,归并就完美的构成了我们的归并算法。

归并算法的JS实现

//假设这就是我们的一堆杂乱无序的牌
let arr=[1,2,4,7,53,8,33,64,5,2,47,61,7];

//归并
function merge(arr,l,m,r){

//左边的牌压入leftArr,右边的牌压入rightArr
//--------start-----------------
let leftArrLen=m-l+1;
let rightArrLen=r-m;
let leftArr=[];
let rightArr=[];

for(var i=0;i<leftArrLen;i++){
leftArr[i]=arr[l+i];
}

for(var j=0;j<rightArrLen;j++){
rightArr[j]=arr[m+j+1];
}

//--------end-----------------

//为两边的两堆牌的最后设置一张无求大的牌,这样在一堆牌耗尽之后暴漏出无求大
//牌,另一堆的牌一定小于这张牌就只会抽取另一堆的牌了
leftArr[leftArrLen]=Infinity;
rightArr[rightArrLen]=Infinity;

//复用i,j减少内存开销,设置为0代表从两堆牌的顶上开始比较
i=0;
j=0;

//k到r就是两堆牌一共的牌数,我们只需要重复这么多次就好,因为每次必定抽出一张
//牌
for(var k=l;k<=r;k++){
//比较抽出较小牌,并通过++j;或++i;达到暴漏出下一张牌的目的
if(leftArr[i]>rightArr[j]){
arr[k]=rightArr[j];
++j;
}else{
arr[k]=leftArr[i];
++i;
}

}

}

//分治和递归
//通过l<r判断,进行分治(m=Math.floor((l+r)/2)),
//再进行递归mergeSort(arr,l,m);mergeSort(arr,m+1,r);
//再由最少的两张牌开始归并 merge(arr,l,m,r);
function mergeSort(arr,l,r){
if(l<r){
let m=Math.floor((l+r)/2);
mergeSort(arr,l,m);
mergeSort(arr,m+1,r);
merge(arr,l,m,r);
}
}

mergeSort(arr,0,arr.length-1);

console.log(arr);


node运行结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息