【问题标题】:most efficient way to sort two sorted array into new sorted array将两个排序数组排序为新排序数组的最有效方法
【发布时间】:2015-10-01 23:02:26
【问题描述】:

我正在尝试将两个 int 数组按升序排序到一个新的 int 数组中。

我是这样写的,它对除 textArr 中的最后一个元素之外的所有内容进行了排序,我不知道为什么......

int i=0, j=0, k=0;
while(i < textArr.length && j < binaryArr.length) {
    if(textArr[i] < binaryArr[j]) {
        mergeArr[k] = textArr[i];
        i++;
    }
    else {
        mergeArr[k] = binaryArr[j];
        j++;
    }
    k++;
}

我环顾四周,找到了一个添加两个新 while 循环的解决方案,但老实说,我不知道后两个 while 循环在做什么。我还想知道这是否是将两个数组排序为第三个排序数组的最有效方法?感谢您的帮助,我对 java 很陌生,想正确学习,显然我想要来了解我实际上在写什么!

int i=0, j=0, k=0;
while(i < textArr.length && j < binaryArr.length) {
    if(textArr[i] < binaryArr[j]) {
        mergeArr[k] = textArr[i];
        i++;
    }
    else {
        mergeArr[k] = binaryArr[j];
        j++;
    }
    k++;
}
while(i < textArr.length) {
    mergeArr[k] = textArr[i];
    i++;
    k++;
}       

【问题讨论】:

  • 这叫做合并。
  • 我只是不明白最后两个 while 循环到底在做什么。
  • 查看正在发生的事情的最佳方法是使用调试器逐步执行算法。
  • 根据你在下面所说的 Paul,我现在明白了,谢谢!如果你把你的答案放在一个答案中,我会把它排除在外。老实说,老实说,我不明白调试器是如何工作的。我通常会在线访问 Java Visualizer,甚至没有考虑过这一点。我也想看看这是否也是最好的方法。另外,如果你有时间,我在下面的评论中有一个超级快速的问题。

标签: java arrays performance sorting


【解决方案1】:

这是您的 cmets 代码,解释了为什么需要最后两个循环。

int[] textArr = {1, 2, 3, 3, 9};
int[] binaryArr = {4, 5, 6};
int[] mergeArr = new int[textArr.length + binaryArr.length];

int i=0, j=0, k=0;
while(i < textArr.length && j < binaryArr.length) {
    if(textArr[i] < binaryArr[j]) {
        mergeArr[k] = textArr[i];
        i++;
    }
    else {
        mergeArr[k] = binaryArr[j];
        j++;
    }
    k++;
}
// At this point either i == textArr.length or j == binaryArr.length
// so you cannot do textArr[i] < binaryArr[j] without getting
// an ArrayIndexOutOfBoundsException. 
// However the algorithm isn't finished. You still need to transfer
// the remaining numbers from one of the original arrays into the answer.
while(i < textArr.length) {
    mergeArr[k] = textArr[i];
    i++;
    k++;
}
while(j < binaryArr.length) {   // It said i in question. I corrected.
    mergeArr[k] = binaryArr[j];
    k++;
    j++;
}

System.out.println(Arrays.toString(mergeArr));

至于这是否是最高效的代码。它和你能得到的一样好。任何算法都必须读取所有数字,所以你不能比O(n + m) 做得更好,其中nm 是原始数组的长度。您可以通过将最终的 while 循环替换为 System.arraycopy 来稍微提高性能。

【讨论】:

    【解决方案2】:

    合并两个大小为n 的排序数组的基本算法。对于更通用的“分别合并两个大小为 mn 的排序数组”,这应该足够了

    //given arrays A, B, create C
    var i, j = 0, k = 0;
    for (i = 0; i < 2n; i++) {
      if (A[j] < B[k]) { 
        C[i] = A[j++]; 
      }
      else { 
        C[i] = B[k++];
      }
    }
    

    【讨论】:

    • 这会抛出一个ArrayIndexOutOfBoundsException。为避免这种情况,您可以使用问题中的方法。
    • 那么在我上面的代码的第二部分中,两个额外的 while 循环到底在做什么?我相信你是对的,保罗,我写了一些非常相似的东西并且得到了一个索引越界异常
    • 使用完其中一个数组中的所有数字后,您将无法再进行比较A[j] &lt; B[k],因为索引(jk)已超出最后一个索引.因此,您需要额外的代码将其他数组中的剩余数字放入答案中。
    • 好的,我想我现在明白了。在这种情况下,由于每个数组中的每个其他数字都排在下一个没有这两个额外循环的情况下,所以我没有得到 binaryArr 数组中的最后一个元素,因为它具有最高的最后一个数字。所以在这种情况下,我是否可以摆脱这两个 while 循环并只分配 binaryArr 的最后一个数字,因为我知道这是怎么回事?那不会被认为是糟糕的代码吗?我可以问你最后一个问题...为什么上面的代码 Collin 给出了超出范围的异常?
    • 对不起,我不明白你的意思。您无法避免在初始循环之后执行某些操作,因为合并尚未完成。而且您不能只从binaryArr 获取最后几个数字,因为您不知道需要从哪个数组中获取它们。我真的认为您应该使用调试器逐步完成此操作。一切都会变得清晰。
    最近更新 更多