算法系列-合并有序数组

来源:互联网 发布:南望王师又一年 知乎 编辑:程序博客网 时间:2024/05/22 16:54

继续算法系列。今天来讲讲如何合并两个有序数组,这也是一个经典的算法设计问题。

问题:

给定两个有序数组(假定为升序),合并成一个有序数组。

例如给定数组

int[] a = { 1, 4, 6, 7, 8 };
int[] b = { 2, 3, 5, 6, 9, 10 };

合并后结果:c={1,2,3,4,5,6,6,7,8,9,10}

思路分析:关键点在于如何确定合并后数组c[i]处的值,应该取得a中的值还是b中的值,还有一个点需要考虑的是如何通过循环来遍历数组值进行比对及当数组长度不一致时,剩余值应该如何处理。

1.比对策略

      很明显可以通过设置数组游标i,j,k来分别指示a,b,c数组中的元素,c[k]=min{a[i],b[j]},c[k]取当前i,j游标指示的两个数组值中的最小值,假设a[i]<b[j] ,应该将a[i]插进c[k]处,同时i,k游标应该后移一位;同样的,反之,应该将b[i]插进c[k]处,同时j,k游标后移。

2.剩余值处理策略

     a,b两个数组长度很可能不一致,当游标 i或j前进至数组末尾时,数组长度较短的一方游标应该终止前进,否则将发生数组越界异常,而数组长度较长的一方游标应该继续前进,并逐个将剩余数字插入到合并后的数组中。

难点分析:虽然思路很清晰了,但要在实际代码实现之时,仍然会遇到一些问题。比如,如何判定两个被合并数组中的哪一个先到达长度末尾,是用if判定?if条件判断的话,又会遇到a,b数组a.length>b.length(a长度大于b长度),a.length<b.length(a长度小于b长度),a.length==b.length(a长度等于b长度),这几种情况。程序流程显得复杂混乱。这里我们在实际操作的时候,采用了while(条件)循环的方式来控制游标的移动,条件则是i<a.length&&j<b.length(注意i,j都从从0开始),条件为false之时,i,j当中必有一个,或者可能全部到达数组末尾,这样一来必有一个数组中的元素被全部插进剩余后的数组中。接下来,我们仍然使用两个while(条件)循环,继续控制游标的移动,a长度较长,则继续移动i,插入a中的剩余元素,同样,若b数组较长,继续移动j,插入b中剩余元素。最后将合并后的数组打印。

参考代码

public class Main {public static void main(String[] args) {// 定义升序数组int[] a = { 1, 4, 6, 7, 8 };int[] b = { 2, 3, 5, 6, 9, 10 };sort(a, b);}public static void sort(int[] a, int[] b) {for (int i : a) {System.out.print(i + ",");}System.out.println();for (int j : b) {System.out.print(j + ",");}// 获取数组长度int len_a = a.length;int len_b = b.length;System.out.println("len_a:" + len_a + ",len_b:" + len_b);int[] result = new int[len_a + len_b];int i, j, k;i = j = k = 0;while (i < len_a && j < len_b) {if (a[i] <= b[j])result[k++] = a[i++];elseresult[k++] = b[j++];}// 处理数组剩余的值,插入结果数组中while (i < len_a)result[k++] = a[i++];while (j < len_b)result[k++] = b[j++];for (int p : result) {System.out.print(p + ",");}}}

特别说明:以上有序数组合并的算法时间复杂度为O(m+n),空间复杂度也是O(m+n),并不是最优算法。这类问题还有好多变形,例如要求对和合并后的元素去重处理,或者假定a,b两个数组中其中一个长度很大,足以容纳a,b所有元素,要求不使用第三个额外数组,算法如何设计等等。这类问题,有兴趣的同学可以自行学习查找资料,我也会在以后的博客中尽量更新出来。如有疏漏和错误之处,敬请批评指正。

0 0