【图文解析】合并两个有序链表


例题描述

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例:

  • 输入:1->2->41->3->4
  • 输出:1->1->2->3->4->4

结点结构体定义

struct ListNode {
	int val;
	struct ListNode *next;
};

解题思路

  1. 首先判断极端条件:l1链表如果为空链表,则不需要进行合并,直接返回另一个链表l2l2链表如果为空链表,直接返回l1链表。
  2. 创建一个新的头指针pHead作为新链表的头指针,初始化为NULL。再创建一个pTail尾指针用来进行尾部插入,初始化为NULL
  3. 创建一个p1指针指向第一个链表的结点,创建另一个p2指针指向第二个链表的结点,通过这两个指针进行操作。
    在这里插入图片描述
  4. 进行新链表的首结点选择
    < 如果 >:p1指针指向的结点数值小于(或等于,不强制归属于此,可置于大于逻辑)p2指针指向的结点val值,说明p1结点的第一个结点值更小,将它置为新链表的首结点,使pHeadpTail都指向p1这个结点,然后使得p1指针指向它的下一个结点。
    < 如果 >:p2指针指向的结点数值大于p1指针指向的结点val值,同理使pHeadpTail都指向p2这个结点,然后使得p2指针指向它的下一个结点。
    【题目中此时都为1p1指向结点值不大于p2指向的结点值,所以将p1指定为新链表的首结点】
    在这里插入图片描述
    更新旧连表指针
    在这里插入图片描述
    【此时新链表的首结点设置完毕,现在有更新后的两个旧链表,下面逻辑进行处理】
  5. 进行链表遍历,循环条件为p1指针与p2指针都不为空,但凡有任一指针为空,说明到达了这个链表的尾部,无法使用循环继续链接,要采用别的代码逻辑处理。
  6. 循环逻辑中,判定两链表结点值的大小
    < 如果 >:p1指向的l1链表中的结点值小于等于p2指向的l2链表中的结点值,那么就将此结点尾插至新链表的尾部,然后将结点的指针更新,使它变成被插入指针的next结点。
    < 否则 >(大于):同理将p2指向的结点尾插到新链表的尾部,更新结点指向。
    在这里插入图片描述
  7. 循环退出条件,任一链表到达结尾。此时我们进行判定:如果是l1链表到达结尾,那么说明l2链表有可能没有结束、或者也结束了,我们将这种情况统一处理:将此时的l2链表链接到新链表的尾部。如果是l2链表同理。
    【题目中此时l1链表到达了尾部,而l2链表还没有到达尾部】
    在这里插入图片描述
    【所以选择将p2指针之后的结点全部"链接"在pTail指向的结点之后】
    在这里插入图片描述
  8. 最终返回新链表的头指针pHead即可。

代码实现

struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {
    if(l1 == NULL){
        return l2;
    }
    if(l2 == NULL){
        return l1;
    }
    struct ListNode *pHead = NULL;
    struct ListNode *pTail = NULL;
    struct ListNode *p1 = l1;
    struct ListNode *p2 = l2;
       
    if(p1->val <= p2->val){
        pHead = pTail = p1;
        p1 = p1->next;
    }
    else{
        pHead = pTail = p2;
        p2 = p2->next;
    }
    
    while(p1 != NULL && p2 != NULL){
        if(p1->val <= p2->val){
            pTail->next = p1;
            p1 = p1->next;
        }
        else{
            pTail->next = p2;
            p2 = p2->next;
        }
        pTail = pTail->next;
    }
    if(p1 == NULL){
        pTail->next = p2;
    }
    if(p2 == NULL){
        pTail->next = p1;
    }
    return pHead;
}

小结

这段程序要保证健壮性,同时可以处理很多“意外情况”,比如我们一开始对新链表头结点的选择时,就要求对两个链表结点值进行比较,从而谨慎的选出较小者作为新链表的头结点,如果不进行这步操作直接执行后面的逻辑,程序就会运行错误。
最后一步链接操作,保证了一个链表的完整性,最后指向了空(NULL),最后的时候其实要考虑循环退出条件,进而处理不同的情况,我们将未到达结尾的链表结点链接在新链表之后就相当于“兵来将挡水来土掩”,可以处理多种情况,效果显著。

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

giturtle

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

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

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

打赏作者

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

抵扣说明:

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

余额充值