Java 如何将一个大小为M的数组合并到另一个大小为2M的数组中

Java 如何将一个大小为M的数组合并到另一个大小为2M的数组中,java,arrays,algorithm,big-o,mergesort,Java,Arrays,Algorithm,Big O,Mergesort,我在一次在线代码挑战中得到了这个问题。我需要将两个排序的数组合并,一个大小为M的M元素,另一个大小为M元素,容量为2M。我提供了以下解决方案: class ArraysSorting { /** * Function to move elements at the end of array * * @param bigger array */ void moveToEnd(int bigger[]) { int i = 0, j = bigger.length - 1;

我在一次在线代码挑战中得到了这个问题。我需要将两个排序的数组合并,一个大小为
M
M
元素,另一个大小为
M
元素,容量为
2M
。我提供了以下解决方案:

class ArraysSorting {

/**
 * Function to move elements at the end of array
 * 
 * @param bigger array
 */
void moveToEnd(int bigger[]) {
    int i = 0, j = bigger.length - 1;
    for (i = bigger.length - 1; i >= 0; i--)
        if (bigger[i] != 0) {
            bigger[j] = bigger[i];
            j--;
        }
}

/**
 * Merges array smaller array of size M into bigger array of size 2M
 * @param bigger array
 * @param smaller array
 */
void merge(int bigger[], int smaller[]) {
    moveToEnd(bigger);
    int i = smaller.length;
    int j = 0;
    int k = 0;
    while (k < (bigger.length)) {
        if ((i < (bigger.length) && bigger[i] <= smaller[j]) || (j == smaller.length)) {
            bigger[k] = bigger[i];
            k++;
            i++;
        } else {
            bigger[k] = smaller[j];
            k++;
            j++;
        }
    }
  }
}
类数组排序{
/**
*函数移动数组末尾的元素
* 
*@param更大的数组
*/
void moveToEnd(整数大于[]){
int i=0,j=更大。长度-1;
对于(i=biger.length-1;i>=0;i--)
如果(大于[i]!=0){
更大的[j]=更大的[i];
j--;
}
}
/**
*将大小为M的较小阵列合并为大小为2M的较大阵列
*@param更大的数组
*@param较小的数组
*/
无效合并(整数较大[],整数较小[]){
移动到末端(更大);
int i=较小的长度;
int j=0;
int k=0;
而(k<(更大的长度)){

如果((i<(biger.length)&&biger[i]你不能超过线性时间,因为你必须至少扫描所有
2M
元素,所以这是你能得到的最好结果

但实际上,您可以进一步优化它。无需将
biger
的元素移到最后;只需将结果从右向左而不是从左向右写入即可(当然,您需要反转比较,在任何步骤中,您都需要选择最大的元素而不是最小的元素)

此外,这也不好:

if ((i < (bigger.length) && bigger[i] <= smaller[j]) || (j == smaller.length)) {
    /* ... */
}
总的来说,我认为您可以使代码更简单,在我看来,这里有一些东西更容易阅读,因为
if
条件更小,更容易理解(它也接近于合并两个数组的传统方式,避免了额外的
O(M)
将元素移到后面的工作):

很容易看出,只要可以比较不同数组中的两个元素,第一个循环就会运行(而不是让循环始终运行并在内部使用复杂的
if
测试)。还要注意的是,由于输出正在写入
biger
,因此一旦第一个循环终止,我们只需确保其余的(如果有)剩下的
较小的
被复制到
较大的
。代码是C语言,但在Java中几乎相同。
较大的
较小的
较大的
较小的
中的元素数;假设
较大的
有足够的空间容纳
较大的
较小的
r_len元素。分配给
较小的
较大的
的初始
if
测试对于处理边缘情况是必要的,在这种情况下,减去1将溢出
大小
的(无符号)范围;在Java中,它们是不必要的,因为Java没有无符号类型(如果我错了,请纠正我,我最近没有使用Java)


时间复杂度仍然保持
O(M)

是的,Java中没有无符号类型,可以使用long而不是int:)
if ((j == smaller.length) || (i < (bigger.length) && bigger[i] <= smaller[j])) {
    /* ... */
}
void merge(int bigger[], size_t bigger_len, int smaller[], size_t smaller_len) {
    ssize_t smaller_i, bigger_i, idx;

    if (smaller_len == 0)
        return;

    smaller_i = smaller_len-1;

    if (bigger_len == 0)
        bigger_i = -1;
    else
        bigger_i = bigger_len-1;

    idx = bigger_len+smaller_len-1;

    while (smaller_i >= 0 && bigger_i >= 0) {
        if (bigger[bigger_i] > smaller[smaller_i]) {
            bigger[idx] = bigger[bigger_i];
            bigger_i--;
        }
        else {
            bigger[idx] = smaller[smaller_i];
            smaller_i--;
        }
        idx--;
    }

    while (smaller_i >= 0) {
        bigger[idx] = smaller[smaller_i];
        smaller_i--;
        idx--;
    }
}