Leetcode之合并两个有序链表

之前虽然对链表有进行学习,但是没有怎么使用过,导致对链表有很大程度的遗忘以及应用过程中遇到了很多问题。

 

题目:合并两个有序链表

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

示例:

输入:1 -> 2 -> 4 ,  1 -> 3 -> 4
输出:1 -> 1 -> 2 -> 3 -> 4 -> 4

题目分析

有序链表:指的是输入的两个链表按从小到大的关系都排好了顺序

新链表是通过拼接给定的两个链表的所有节点组成的:不能定义新的链表的返回,需要使用原先的节点。

示例给的并不是太清楚,这里给出一个更清晰的示例:

输入:1 -> 3 -> 4 ,  2 -> 5 -> 7
输出:1 -> 2 -> 3 -> 4 -> 5 -> 7

简单的来说,这个题目就是要求我们将两个排好序的链表,将他们的节点拆分,重新拼接成一个从小到大排列的链表。这里我们有些便利我们需要利用上,输入链表是有序的,所以我们不需要将链表遍历然后重新排序,直接按序读取进行比较即可。

这里我们使用方法是

1.先判断链表l1和l2是否有为空的情况,若其中一条表为空,则直接返回另一条链表。

2.在两条链表皆不为空的情况下,先创建一个头结点(后面会释放掉),并且创建一个链表指针,指向头结点。

3.然后开始循环判断两条链表当前节点数据域内的数据的大小,那条链表上当前节点数据域数据小,就将那条链表接到新创             建的头结点上。

4.重复第三步,直到有一条链表为空为止,然后再将另一条链表剩余部分接到新的链表上。

5.将链表指针指向新链表的头结点,然后释放头结点并返回新链表。

 

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    
    if (l1 == NULL)    //链表1为空,直接返回链表2
        return l2;

    if (l2 == NULL)    //同上,这里用于检测到一条链表为空时快速返回结果,提高函数效率
        return l1;

    struct ListNode *head = (struct ListNode*)malloc(sizeof(struct ListNode));    //创建头节点

    struct ListNode *temp = head;
    head->next = NULL;

    while((l1 != NULL) && (l2 != NULL))     //两条链表皆不为空,比较他们当前数据域内的数据大小,谁小就将谁接到新链表上
    {
        if (l1->val < l2->val)
        {
            temp->next = l1;                //将l1链表当前节点接到新链表上
            temp = temp->next;              //保存节点              
            l1 = l1->next;                  //l1指向后一个节点
            temp->next = NULL;              //将新链表和l1链表断开连接
        }
        else
        {
            temp->next = l2;
            temp = temp->next;
            l2 = l2->next;
            temp->next = NULL;
        }
    }

    while((l1 != NULL))                      //当一条链表为空之后,将另一条链表剩余部分都接到新链表上
    {
        temp->next = l1;
        temp = temp->next;     
        l1 = l1->next;
        temp->next = NULL;
    }

    while((l2 != NULL))
    {
        temp->next = l2;
        temp = temp->next;     
        l2 = l2->next;
        temp->next = NULL;
    }

    temp = head->next;                       //将temp指向新链表头,用于返回新链表

    free(head);                              //释放之前申请的内存,否则不符合题目要求,创建了新的节点

    return temp;
   
}

 

部分程序图例

在该段程序当中,相对难理解的就是在链表节点拼接部分,这里将该部分程序用图解来分析程序执行过程。

if (l1->val < l2->val)
{
    temp->next = l1;                //将l1链表当前节点接到新链表上
    temp = temp->next;              //保存节点              
    l1 = l1->next;                  //l1指向后一个节点
    temp->next = NULL;              //将新链表和l1链表断开连接
}

假设:( l1 -> val  < l2 ->  val )

1.该段程序第一步 temp->next = l1; 通过temp的指针域将头结点和链表l1连接。

2.第二步 temp = temp->next; 将temp指针后移一个节点,并且保存l1的第一个节点。此时temp 与 l1相等,上图中的表达式有误。

3.第三步 l1 = l1->next; 将l1指针后移一个节点。

4.将新链表和l1链表断开。

 

这里我当初遇到了两个疑问:

为什么第一步不能使用 temp = l1;  ?

为什么第三和第四步不能互换

这里如果有分析清楚上面的图示应该已经清楚这两个问题的原因了。

第一个问题,使用temp->next = l1; 是我们需要使用节点指针域来将节点和链表连接,假如我们使用temp = l1;则对temp的操作等同对l1进行操作,不能将l1和temp的操作分开。

第二个问题,第二步完成后,temp和l1指向同一个节点,若是我们不将l1指针向后移一个节点,直接将新链表和l1链表从当前节点断开,会导致l1链表剩下节点永久丢失,因为我们没有保存l1剩下链表的头指针。单向链表只能通过上一个节点找到下一个节点。

 

仓促成文,不当之处,尚祈方家和读者批评指正。联系邮箱1772348223@qq.com 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值