将两个有序数组合并到一起

给出两个有序的整数数组A和B,请将数组B合并到数组A中,变成一个有序的数组

注意:

可以假设A数组有足够的空间存放B数组的元素,A和B中初始的元素数目分别为m和n

 

暴力:t((n+m)*log(m+n))  s(1)

System.arraycopy(源数组, 源数组起始位置, 目标数组, 目标数组起始位置, 复制的长度); 方法实现复制:

解题思路;

1.将B复制到A后面

2.整体排序(没有用到A,B有序的条件)

import java.util.*;
public class Solution {
    public void merge(int A[], int m, int B[], int n) {
          System.arraycopy(B,0,A,m,n);
          Arrays.sort(A);
    }
}

双指针 / 从前往后 T(n+m),s(n+m)

解题思路;

1.复制A 到A_copy;

2.p1指向A_copy,p2指向B,p指向A,同时遍历A_copy,和B,小的放在A中

3.B结束,剩下A_copy,直接放到A中

4.A_copy结束,剩下B,,直接放到A中

import java.util.*;
public class Solution {
    public void merge(int A[], int m, int B[], int n) {
        int[] A_copy=new int[m];//A_copy用来记录A
        System.arraycopy(A,0,A_copy,0,m);//A_copy复制A
        //p1指向A,p2指向B
           int p1=0;
           int p2=0;
           int p=0;
           while((p1<m) &&(p2<n)){
               A[p++]=(A_copy[p1]>B[p2])?B[p2++]:A_copy[p1++];
           }
           //B结束,剩下A——copy
           if(p1<m){
               System.arraycopy(A_copy,p1,A,p1+p2,m+n-p1-p2);
           }
           //A_copy结束,剩下B
           if(p2<n){
            System.arraycopy(B,p2,A,p1+p2,m+n-p1-p2);
        }
    }
}

双指针 / 从后往前  T(n+m)   s(1)

 解题思路:

1.p1指向A尾巴,p2指向B尾巴,p指向A和B的长度之和,同时遍历A和B,大的放在p指的位置中

3.B结束,剩下A,直接放到A中,不用遍历(p1和p重合)

4.A结束,剩下B,,直接复制到A中,个数是p2+1

import java.util.*;
public class Solution {
    public void merge(int A[], int m, int B[], int n) {
               int p1=m-1;
               int p2=n-1;
               int p=m+n-1;
               while(p1>=0 && p2>=0){
                   A[p--]=(A[p1]>B[p2])?A[p1--]:B[p2--];
               }
              //A遍历结束了,剩下了B
               System.arraycopy(B,0,A,0,p2+1);
    }
}

 

<think> 我们正在讨论C语言中合并两个数组的方法。根据之前的引用,用户提到了两种场景:连接字符串数组合并有序数组。我将分别讨论这两种情况,并给出相应的代码示例。 首先,对于一般的数组合并(不考虑顺序),我们可以简单地使用循环将两个数组的元素复制到一个数组中。对于字符串数组,我们可以使用字符串函数来简化操作。 其次,对于有序数组合并,我们可以使用双指针法(归并思想)来高效地合并两个有序数组,这在引用[2]和引用[3]中都有提及。 下面我将详细说明: 一、一般数组合并(包括字符串数组) 步骤: 1. 定义两个数组,并计算它们的长度。 2. 创建一个数组,其长度为两个数组长度之和。 3. 使用循环将第一个数组的元素复制到新数组。 4. 使用循环将第二个数组的元素复制到新数组的剩余部分。 示例代码(合并两个整型数组): ```c #include <stdio.h> int main() { int arr1[] = {1, 2, 3}; int arr2[] = {4, 5, 6}; int n1 = sizeof(arr1) / sizeof(arr1[0]); int n2 = sizeof(arr2) / sizeof(arr2[0]); int n3 = n1 + n2; int arr3[n3]; // 复制第一个数组 for (int i = 0; i < n1; i++) { arr3[i] = arr1[i]; } // 复制第二个数组 for (int i = 0; i < n2; i++) { arr3[n1 + i] = arr2[i]; } // 打印合并后的数组 for (int i = 0; i < n3; i++) { printf("%d ", arr3[i]); } return 0; } ``` 如果是字符串数组(即字符数组),我们可以使用字符串处理函数,如`strcpy`和`strcat`。但需要注意的是,目标数组必须足够大以容纳两个字符串(包括结束符'\0')。 示例代码(合并两个字符串数组): ```c #include <stdio.h> #include <string.h> int main() { char s1[100] = "Hello, "; char s2[] = "World!"; // 使用strcat连接两个字符串,注意s1必须有足够的空间 strcat(s1, s2); printf("%s", s1); // 输出: Hello, World! return 0; } ``` 二、合并两个有序数组(不开辟新空间) 引用[2]中提到的问题:有两个有序数组,将第二个数组合并到第一个数组中,第一个数组有足够的空间(后面有0作为占位)。我们可以使用双指针法从后往前合并,避免覆盖第一个数组的有效元素。 步骤: 1. 初始化两个指针分别指向两个数组有效部分的末尾(注意:第一个数组后面有占位0,所以有效部分是指非0部分)。 2. 再初始化一个指针指向第一个数组的最后一个位置(即合并数组的末尾)。 3. 从后往前比较两个数组的元素,将较大的元素放到合并数组的末尾,并移动相应的指针。 4. 如果第二个数组还有剩余,则继续复制。 示例代码(合并两个有序整型数组): ```c #include <stdio.h> void merge(int* nums1, int m, int* nums2, int n) { int p1 = m - 1; // 指向nums1的最后一个有效元素 int p2 = n - 1; // 指向nums2的最后一个元素 int p = m + n - 1; // 指向合并数组的末尾 // 从后往前比较并填充 while (p1 >= 0 && p2 >= 0) { if (nums1[p1] > nums2[p2]) { nums1[p] = nums1[p1]; p1--; } else { nums1[p] = nums2[p2]; p2--; } p--; } // 如果nums2还有剩余元素,复制到nums1的前面 while (p2 >= 0) { nums1[p] = nums2[p2]; p--; p2--; } } int main() { int nums1[6] = {1,2,3,0,0,0}; int nums2[3] = {2,5,6}; merge(nums1, 3, nums2, 3); // 打印合并后的数组 for (int i = 0; i < 6; i++) { printf("%d ", nums1[i]); // 输出:1 2 2 3 5 6 } return 0; } ``` 注意:这个方法要求第一个数组有足够的空间来容纳两个数组的所有元素。 三、合并两个有序数组(开辟新空间) 如果允许开辟新空间,那么我们可以使用双指针法(从前往后)将两个有序数组合并一个数组中。 示例代码: ```c #include <stdio.h> #include <stdlib.h> int main() { int arr1[] = {1,3,5}; int arr2[] = {2,4,6}; int n1 = sizeof(arr1) / sizeof(int); int n2 = sizeof(arr2) / sizeof(int); int n3 = n1 + n2; int* arr3 = (int*)malloc(n3 * sizeof(int)); int i = 0, j = 0, k = 0; while (i < n1 && j < n2) { if (arr1[i] < arr2[j]) { arr3[k++] = arr1[i++]; } else { arr3[k++] = arr2[j++]; } } // 处理剩余元素 while (i < n1) { arr3[k++] = arr1[i++]; } while (j < n2) { arr3[k++] = arr2[j++]; } // 打印 for (i = 0; i < n3; i++) { printf("%d ", arr3[i]); } free(arr3); return 0; } ``` 总结: 1. 普通数组合并:直接复制,注意数组长度。 2. 字符串合并:使用`strcat`,但要确保目标数组有足够空间。 3. 有序数组合并(不开辟新空间):双指针从后往前合并(要求第一个数组后面有足够空间)。 4. 有序数组合并(开辟新空间):双指针从前往后合并。 根据实际需求选择合适的方法。 相关问题: 1. 在C语言中如何动态分配数组合并两个数组? 2. 合并两个有序数组时,如果要求降序排列该如何修改? 3. 在合并字符串时,如何防止目标数组溢出? 4. 在不开辟新空间合并有序数组时,如果第一个数组的空间不是足够大会发生什么? </think> ### C语言数组合并方法详解 在C语言中合并数组需要根据数组类型(普通数组、字符串、有序数组)选择合适的方法。以下是三种典型场景的操作方法: --- #### 一、普通数组合并(无序) 通过循环复制实现数组合并: ```c #include <stdio.h> int main() { int arr1[3] = {1, 3, 5}; // 数组1 int arr2[3] = {2, 4, 6}; // 数组2 int merged[6]; // 合并数组 // 计算数组长度 int len1 = sizeof(arr1)/sizeof(arr1[0]); int len2 = sizeof(arr2)/sizeof(arr2[0]); // 合并操作 for(int i=0; i<len1; i++) { merged[i] = arr1[i]; // 复制数组1 } for(int i=0; i<len2; i++) { merged[len1 + i] = arr2[i]; // 复制数组2 } // 输出结果: 1 3 5 2 4 6 for(int i=0; i<len1+len2; i++) { printf("%d ", merged[i]); } return 0; } ``` **特点**: - 时间复杂度:$O(n)$ - 需要额外空间存放合并结果 - 保持原数组顺序但无序合并 --- #### 二、字符串数组合并 使用`strcpy`和`strcat`库函数[^1]: ```c #include <stdio.h> #include <string.h> int main() { char s1[50] = "Hello"; // 目标数组需足够大 char s2[] = " World!"; strcat(s1, s2); // 将s2连接到s1末尾 printf("%s", s1); // 输出: Hello World! return 0; } ``` **注意事项**: 1. 目标数组必须预留足够空间(包括结束符`\0`) 2. 使用前需包含`string.h`头文件 3. 避免缓冲区溢出风险 --- #### 三、有序数组合并(不开辟新空间) 双指针法实现原地合并[^2][^3]: ```c #include <stdio.h> void merge(int* nums1, int m, int* nums2, int n) { int p1 = m - 1; // nums1有效元素末尾 int p2 = n - 1; // nums2末尾 int p = m + n - 1; // 合并位置 // 从后向前合并 while (p1 >= 0 && p2 >= 0) { if (nums1[p1] > nums2[p2]) { nums1[p--] = nums1[p1--]; } else { nums1[p--] = nums2[p2--]; } } // 处理nums2剩余元素 while (p2 >= 0) { nums1[p--] = nums2[p2--]; } } int main() { int nums1[6] = {1, 3, 5, 0, 0, 0}; // 预留空间 int nums2[3] = {2, 4, 6}; merge(nums1, 3, nums2, 3); // 原地合并 // 输出: 1 2 3 4 5 6 for (int i = 0; i < 6; i++) { printf("%d ", nums1[i]); } return 0; } ``` **算法要点**: 1. 使用三指针策略($p1$, $p2$, $p$) 2. 时间复杂度:$O(m+n)$ 3. 空间复杂度:$O(1)$ 4. 要求首个数组有足够预留空间 --- ### 方法对比 | 方法 | 适用场景 | 空间复杂度 | 特点 | |--------------|-------------------|------------|--------------------------| | 循环复制 | 普通无序数组 | $O(n)$ | 实现简单,需额外空间 | | `strcat` | 字符串数组 | $O(1)$ | 专为字符串优化 | | 双指针法 | 有序数组 | $O(1)$ | 原地操作,高效有序合并 | > **选择建议**: > - 普通数组合并 → 循环复制法 > - 字符串合并 → `strcat`函数[^1] > - 有序数组合并 → 双指针法[^2][^3]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值