合并两个有序列表(双指针)

这篇博客介绍了一个合并两个有序链表的算法,通过使用双指针同步遍历两个链表,每次都选择较小的节点加入到新的链表中。当其中一个链表遍历完后,将另一个未遍历完的链表连接到新链表的末尾。这种方法确保了合并后的链表依然有序。

相信做过“合并两个有序数组”这样操作的同学这题应该没有问题

我们的想法主要是建立一个新的链表来存储合并后的链表,我们同时遍历两个链表,一个一个对应去比较,每次都选那个结点值小的,然后没选到的结点不动(等着参加下一次比较),被选到的就向前走一步,这样一直循环比较直到有一个链表走完了,我们就break

最后把那个没走完的链表直接拼在后面即可

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public://双指针
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        if(list1==nullptr&&list2==nullptr)//排除两个链表都空的情况
        {
            return NULL;
        }
        ListNode *head=new ListNode;//建立新链表
        ListNode* p=head;//复制头结点
        while(list1!=nullptr&&list2!=nullptr)
        {
            if(list1->val<list2->val)
            {
                p->next=list1;
                list1=list1->next;
            }
            else
            {
                p->next=list2;
                list2=list2->next;
            }
            p=p->next;//注意每次我们的新链表都要向前一步走
        }
        if(list1!=nullptr)
        {
            p->next=list1;
        }
        else if(list2!=nullptr)
        {
            p->next=list2;
        }
        
        return head->next;//注意返回的是head->next(因为head没有填入值)
    }
};

<think>好的,我现在需要帮用户解决如何用C语言通过指针实现合并两个有序数组的问题。用户明确要求使用指针和示例代码,所以我得先回顾相关的知识。 首先,合并两个有序数组通常有两种方法:一种是创建一个临时数组,然后逐个比较元素,把较小的放入临时数组,最后复制回去。不过用户提供的引用中提到,比如引用[2]和引用[3]都提到了双指针的方法,尤其是从后往前合并,这样可以在不使用额外空间的情况下完成任务,特别是当第一个数组有足够的空间时。例如,题目中的nums1数组可能有足够的容量,如LeetCode的88题,这种情况下从后往前比较可以避免覆盖原数据。 用户提到使用指针,所以我需要考虑如何用指针操作而不是数组下标。指针操作的话,需要移动指针来访问元素,同时注意边界条件。 根据引用[3]中的方法,双指针两个数组的末尾开始比较,较大的元素放到合并后的末尾。这样可以避免覆盖nums1中未处理的元素,特别是当nums1本身有足够空间时。这种方法不需要额外空间,效率也高。 现在需要将这种方法转化为C语言的代码。首先确定参数,比如两个数组arr1和arr2,它们的大小m和n。假设arr1有足够的空间容纳合并后的数组,总长度为m+n。例如,LeetCode的题目通常这样设定。 代码的大致步骤应该是: 1. 初始化三个指针:p1指向arr1的最后一个有效元素(即m-1位置),p2指向arr2的最后一个元素(n-1位置),p指向合并后的末尾(m+n-1位置)。 2. 从后往前遍历,比较p1和p2所指的值,将较大的放到p的位置,然后相应指针前移。 3. 当其中一个数组处理完后,如果arr2还有剩余元素,需要复制到arr1的前面位置。 需要注意的是,如果使用指针的话,可能需要用指针变量来跟踪当前位置,而不是使用整数索引。例如,定义int *p1 = arr1 + m -1;,类似的,p2和p也是如此。 然后,编写代码的时候要注意边界情况,比如其中一个数组为空,或者元素全部合并后另一个数组还有剩余元素。 根据引用[2]中的思路,如果使用临时数组的话需要malloc,但用户可能更希望不需要额外空间的解法,所以优先考虑从后往前的双指针方法。 现在,把这些思路转化为具体的代码。例如: void merge(int* nums1, int m, int* nums2, int n) { int *p1 = nums1 + m - 1; int *p2 = nums2 + n - 1; int *end = nums1 + m + n - 1; while (p1 >= nums1 && p2 >= nums2) { if (*p1 > *p2) { *end-- = *p1--; } else { *end-- = *p2--; } } // 处理剩余的nums2元素 while (p2 >= nums2) { *end-- = *p2--; } } 这样,代码利用了三个指针,从后往前合并,无需额外空间。同时,如果nums1的元素先处理完,剩下的nums2元素可以直接复制到nums1的前面。如果nums2先处理完,剩下的nums1元素已经在正确的位置,无需处理。 测试一下这个代码是否正确。例如,nums1 = [1,3,5,0,0,0], m=3, nums2 = [2,4,6], n=3。合并后应该得到[1,2,3,4,5,6]。代码中,p1指向5,p2指向6,比较后放入末尾,依次类推。最后如果p2还有剩余,比如当nums1处理完但nums2还有元素时,需要继续复制。 另外,需要考虑m或n为0的情况。例如,如果n=0,则不需要处理。代码中的循环会自动跳过,直接返回nums1。同样,如果m=0,则直接将nums2复制到nums1中。 用户可能需要示例代码,所以需要提供完整的函数实现,并注释说明。同时,确保指针操作正确,不会越界。 总结,正确的做法是使用三个指针,从后往前合并,这样可以高效且不需要额外空间,符合用户的需求。</think>以下是使用指针实现合并两个有序数组的C语言示例代码及详细说明: ```c #include <stdio.h> void merge(int* nums1, int m, int* nums2, int n) { // 初始化三个指针:分别指向nums1末尾、nums2末尾、合并后数组末尾 int* p1 = nums1 + m - 1; int* p2 = nums2 + n - 1; int* end = nums1 + m + n - 1; // 逆向比较填充(避免覆盖未处理的nums1元素) while (p1 >= nums1 && p2 >= nums2) { *end-- = (*p1 > *p2) ? *p1-- : *p2--; } // 处理剩余元素(只需要处理nums2剩余情况) while (p2 >= nums2) { *end-- = *p2--; } } // 测试代码 int main() { int nums1[6] = {1, 3, 5, 0, 0, 0}; int nums2[] = {2, 4, 6}; merge(nums1, 3, nums2, 3); printf("合并结果:"); for (int i = 0; i < 6; i++) { printf("%d ", nums1[i]); } return 0; } ``` 代码说明: 1. **指针初始化**:`p1`指向nums1最后一个有效元素,`p2`指向nums2最后一个元素,`end`指向合并后数组的末尾位置 2. **逆向合并**:通过`while`循环比较两个指针指向的元素,将较大值放入`end`位置,并移动对应指针 3. **剩余处理**:当nums1元素处理完后,若nums2仍有剩余元素,直接复制到nums1前端 实现原理: 该算法利用$O(1)$空间复杂度完成合并,时间复杂度为$O(m+n)$。通过从后向前遍历的方式,避免了正向合并需要移动元素的额外操作[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZZZWWWFFF_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值