JavaScript算法-合并排序(分治策略)

合并排序

将排序数组拆分成若干个子数组, 然后进行合并

 \large Time=\Theta (nlgn)

Space ~ O(n)

第一步合并两个已排序数组

  • 方法一

对所有元素进行插入排序

\large Time = O(n^{2})

  • 方法二

对所有元素执行 Array.sort  ---不在算法考量内

\large Time = O(nlgn)

  • 方法三

运用分治策略,拆分成两部分进行合并

假设现有数组[11,33,55,22,44] 

图解分析(寻找循环不变式)

AA1A2k=A回写位置,i=A1,j=A2
[11,33,55,22,44] [11,33,55,Infinity] [22,44,Infinity] k=0;  i=0;  j=0
[11,33,55,22,44] [11,33,55,Infinity] [22,44,Infinity] k=1;  i=1;  j=0
[11,22,55,22,44] [11,33,55,Infinity] [22,44,Infinity] k=2;  i=1;  j=1
[11,22,33,22,44] [11,33,55,Infinity] [22,44,Infinity] k=3;  i=2;  j=1
[11,22,33,44,44] [11,33,55,Infinity] [22,44,Infinityk=4;  i=2;  j=2
[11,22,33,44,55[11,33,55,Infinity[22,44,Infinityk=5;  i=3;  j=2

 

A1,A2分别添加Infinity 无穷大,是个哨兵位置,保证最后一个可比较回写的值必定比另一个区域的最后一个值小,当A中k指向的回写位置超出数组位置,终止循环.

代码实现合并两个有序数组

function merge(A, l, p, r){
    //l 数组左边界
    //p 数组分界位置
    //r 数组右边界 (边界位置左闭右开)
    let A1 = A.slice(l,p), A2 = A.slice(p,r);
    A1.push(Infinity)
    A2.push(Infinity) //设置哨兵位置
    for(let k=l, i=0, j=0; k<r; k++){
        A[k] = A1[i]<A2[j]?A1[i++]:A2[j++]
    }
}

合并排序

  • 合并排序的步骤

1.把需要处理的数组进行拆分,直至最小粒度为单个元素(单个元素即有序的数组如 [1] )

2.然后开始对每个有序数组进行合并即上述的合并两个已排序数组

3.合并完成后即已完全排列的数组

  • 图表分析
步骤一:拆分步骤二:合并
[11,33,55,77,99,22,44,66] [11]   [33]   [55]   [77]   [99]   [22]   [44]   [66] 
[11,33,55,77]   [99,22,44,66] [11,33]   [55,77]   [22,99]   [44,66] 
[11,33]   [55,77]   [99,22]   [44,66] [11,33,55,77]   [22,44,66,99] 
[11]   [33]   [55]   [77]   [99]   [22]   [44]   [66] [11,22,33,44,55,66,77,99]

 

  • 代码实现
function merge(A, l, p, r){
    let A1 = A.slice(l, p), A2 = A.slice(p, r);
    A1.push(Infinity)
    A2.push(Infinity)
    for(let k=l, i=0, j=0; k<r; k++){
        A[k] = A1[i]<A2[j]?A1[i++]:A2[j++]
    }
}

function mergeSort(A, l, r){
    if(r-l < 2) {return}  //如果长度小于2即只有一个或零个长度 本身有序不用排序
    const p = Math.ceil((l+r)/2); //获取一个中心位置进行拆分
    mergeSort(A, l, p)  //左半部分持续拆分
    mergeSort(A, p, r)  //右半部分持续拆分
    merge(A, l, p, r)  //拆分完成进行合并
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值