力扣 21. 合并两个有序链表 C语言实现

题目描述:

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

题目链接

方法1:遍历

新建一个链表 newList 用于存放合并后的链表,设置一个指针指向该链表最后一个位置的 next,分别判断两个链表当前位置的大小,将值小的元素插入 newList 的末尾,并向后移动当前链表的位置,直到两个链表中有一个链表为空。然后再依次查看哪个链表不为空,将不为空的链表剩下的元素插入 newList 中。

其中需要考虑的问题是应该如何向 newList 中插入元素。首先创建一个 newList 指针并指向空,同时创建一个指向newList末尾结点的指针 last,令 last=newList。

例如实例1,l1和l2初始时都指向头结点,判断头结点的元素大小,得到 l2的元素,确定元素后将该元素赋值给一个 cur 指针,由于当前 newList 指向为空,所以此时要让 newList=cur,并让last=newList,同时,也要让 l2 链表的当前位置向后移动,也就是 l2 = l2->next。保证每次last指向的都是newList的最后一个元素。当newList不为空时,将确定的元素赋给cur指针后,将newList末尾的指针的下一个指向cur,即 last->next=cur,然后再更新last的位置。让 last = last->next. 依次遍历,最后返回 newList。

代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    struct ListNode* newList=NULL;
    if(list1==NULL && list2==NULL)
    {
        return newList;
    }
    struct ListNode* last=newList;
    while(list1!=NULL && list2!=NULL)
    {

        if(list1->val < list2->val)
        {
            struct ListNode* cur = (struct ListNode*)malloc(sizeof(struct ListNode));
            cur->val = list1->val;
            cur->next = NULL;
            if(newList==NULL)
            {
                newList = cur;
                last = newList;
            }
            else
            {
                last->next = cur;
                last = last->next;
            }
            list1 = list1->next;
        }
        else
        {
            struct ListNode* cur = (struct ListNode*)malloc(sizeof(struct ListNode));
            cur->val = list2->val;
            cur->next = NULL;
            if(newList==NULL)
            {
                newList = cur;
                last = newList;
            }
            else
            {
                last->next = cur;
                last = last->next;
            }
            list2 = list2->next;
        }
    }
    while(list1!=NULL)
    {
        struct ListNode* cur = (struct ListNode*)malloc(sizeof(struct ListNode));
            cur->val = list1->val;
            cur->next = NULL;
            if(newList==NULL)
            {
                newList = cur;
                last = newList;
            }
            else
            {
                last->next = cur;
                last = last->next;
            }
            list1 = list1->next;
    }
    while(list2!=NULL)
    {
        struct ListNode* cur = (struct ListNode*)malloc(sizeof(struct ListNode));
            cur->val = list2->val;
            cur->next = NULL;
            if(newList==NULL)
            {
                newList = cur;
                last = newList;
            }
            else
            {
                last->next = cur;
                last = last->next;
            }
            list2 = list2->next;
    }
    return newList;
}

对于 newList 为空的情况,每次循环都需要进行判断较为麻烦,所以在 创建 newList 的时候,首先创建一个值为-1 的节点,令 last指向 newList,然后直接按照上述newList不为0的情况判断即可。遍历完两个链表并将值都赋给 newList后,返回值返回newList->next,跳过第一个元素。

改进后代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    struct ListNode* newList=(struct ListNode*)malloc(sizeof(struct ListNode));
    newList->val = -1;
    newList->next = NULL;
    if(list1==NULL && list2==NULL)
    {
        return newList->next;
    }
    struct ListNode* last=newList;
    while(list1!=NULL && list2!=NULL)
    {

        if(list1->val < list2->val)
        {
            struct ListNode* cur = (struct ListNode*)malloc(sizeof(struct ListNode));
            cur->val = list1->val;
            cur->next = NULL;
            last->next = cur;
            last = last->next;
            list1 = list1->next;
        }
        else
        {
            struct ListNode* cur = (struct ListNode*)malloc(sizeof(struct ListNode));
            cur->val = list2->val;
            cur->next = NULL;
            last->next = cur;
            last = last->next;
            list2 = list2->next;
        }
    }
    while(list1!=NULL)
    {
        struct ListNode* cur = (struct ListNode*)malloc(sizeof(struct ListNode));
            cur->val = list1->val;
            cur->next = NULL;
            last->next = cur;
            last = last->next;
            list1 = list1->next;
    }
    while(list2!=NULL)
    {
        struct ListNode* cur = (struct ListNode*)malloc(sizeof(struct ListNode));
            cur->val = list2->val;
            cur->next = NULL;
            last->next = cur;
            last = last->next;
            list2 = list2->next;
    }
    return newList->next;
}

然而后来发现上面两种方法都不太好,每次都需要创建新的结点,继续改进代码:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    struct ListNode* newHead = NULL;
    newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
    newHead->val = -1;
    newHead->next = NULL;
    struct ListNode* cur = newHead;
    while(list1 && list2)
    {
        if(list1->val < list2->val)
        {
            cur->next = list1;
            list1 = list1->next;
            
        }
        else
        {
            cur->next = list2;
            list2 = list2->next;
        }
        cur = cur->next;
    }
    if(list1)
    {
        cur->next = list1;
    }
    else if(list2)
    {
        cur->next = list2;
    }
    return newHead->next;
}

方法2:递归

使用递归不需要创建一个新的链表,直接在现有的两个链表中进行排序。 如下图,现在两个链表合并的函数是mergeTwoLists(L1, L2)

如上图,当前合并的链表应该为 L2->next = mergeTwoLists(L1, L2->next)

 对于这次,应该为L1->next = mergeTwoLists(L1->next, L2) 

递归的核心在于,只关注当前层要干什么,返回什么,至于我的下一层是不管的。

如果L1空,则返回L2,如果L2为空,则返回L1,这就是终止条件

如果L1第一个元素小于L2的, 那么就要把L1的这个元素放到最前面,至于后面的那串长啥样 ,不需要考虑. 我只要令当前的下一个节点等于下一层(令L1->next = 下一层)就行。

最终需要返回的就是当前节点加下一层。

代码如下 

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    if(list1==NULL)
    {
        return list2;
    }
    if(list2==NULL)
    {
        return list1;
    }
    if(list1->val < list2->val)
    {
        list1->next = mergeTwoLists(list1->next, list2);
        return list1;
    }
    else
    {
        list2->next = mergeTwoLists(list1, list2->next);
        return list2;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值