【C语言刷题】合并两个有序链表&反转链表

活动地址:CSDN21天学习挑战赛

文章目录

  • Leetcode21——合并两个有序链表
    • 题目描述
    • 思路分析和代码实现(C语言)
  • Leetcode206——反转链表
    • 题目描述
    • 思路分析与代码实现(C语言)
      • 1.新链表头插法
      • 2.三指针逆置法

Leetcode21——合并两个有序链表

题目描述

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

示例 1:
**输入:**l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]

【C语言刷题】合并两个有序链表&反转链表_第1张图片

示例 2:
**输入:**l1 = [ ], l2 = [ ] 输出:[ ]

示例 3:
**输入:**l1 = [ ], l2 = [0] 输出:[0]

提示:

  • 两个链表的节点数目范围是 [0, 50]
  • -100 <= Node.val <= 100
  • l1 和 l2 均按 非递减顺序 排列

核心代码模式

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


struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{

}

思路分析和代码实现(C语言)

思路其实很简单,这里用了哨兵结点作为新链表的头结点,用两个指针把两个链表中的结点互相比较,小的先尾插到新链表中,总会有一条链表先插完,没插完的链表把剩下的结点一次尾插到新链表。有一些要注意的点,首先创建了哨兵结点,定义了guard指针指向哨兵结点,这时应该立即给哨兵结点的next指针初始化为NULL,不然有野指针的潜在风险。定义两个指针cur1和cur2分别对应list1链表和list2链表,while循环的条件应当是cur1&&cur2,为什么呢?这样的话只要有一个链表先插完就立马跳出循环。在循环结束后要根据哪个链表还没插完,把剩余结点全部尾插到新链表。我们这里使用的辅助结点——哨兵结点是题目没提供的,我们应当在最后将其释放,不过释放前得先把哨兵结点的next指针的内容取出来,作为头指针返回。

image.png
代码实现

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
    struct ListNode* cur1 = list1;
    struct ListNode* cur2 = list2;
    struct ListNode* guard = (struct ListNode*)malloc(sizeof(struct ListNode));
    guard->next = NULL;
    struct ListNode* tail = guard;
    
    while(cur1 && cur2)
    {
        if(cur1->val > cur2->val)
        {
            tail->next = cur2;
            tail = tail->next;
            cur2 = cur2->next;
        }
        else
        {
            tail->next = cur1;
            tail = tail->next;
            cur1 = cur1->next;
        }
    }

    if(cur1)
        tail->next = cur1;
    if(cur2)
        tail->next = cur2;

    struct ListNode* head = guard->next;
    free(guard);
    return head;
}

Leetcode206——反转链表

题目描述

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

链接:Leetcode206

示例

示例 1:
**输入:**head = [1,2,3,4,5] 输出:[5,4,3,2,1]

【C语言刷题】合并两个有序链表&反转链表_第2张图片

示例 2:
**输入:**head = [1,2] 输出:[2,1]

【C语言刷题】合并两个有序链表&反转链表_第3张图片

示例 3:
**输入:**head = [] 输出:[]

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

核心代码模式

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


struct ListNode* reverseList(struct ListNode* head)
{
    
}

思路分析与代码实现(C语言)

1.新链表头插法

实际上有一道题和这个基本一样,只是要求的是使用数组,而这里使用的是单链表。思路也是可以借鉴互通的,不妨创建一个新的链表,不过相比于数组,这里不需要开辟新结点,只是把结点间的指向关系进行修改。定义一个新的头指针newHead,定义一个查找当前结点的cur指针,查找下一结点的next指针,只要cur不指向NULL,就把cur指向的结点放到新链表去,怎么放呢?把newHead的内容给cur指向结点的next指针,让它指向newHead原来指向的东西,再把cur指向结点的地址给newHead,让newHead指向该结点,不过要注意在执行这些操作之前要先把cur->next的值放到next去,在执行完后要把next的值再放到cur去。其实也就是让原来的结点从前向后一个一个头插到新链表中。
image.png
代码实现

struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode* cur = head;
    struct ListNode* newHead = NULL;

    while(cur)
    {
        struct ListNode* next = cur->next;
        cur->next = newHead;
        newHead = cur;
        cur = next;
    }

    return newHead;
}

2.三指针逆置法

有没有想过这样一种方法,既然链表是通过指针联系的,那把指针指向关系逆转了不就能实现反转了吗,用三个指针,分别指向前一结点、当前结点和下一结点(prev、cur、next),只要cur指向不为NULL,就说还有结点没有反转,就把前一结点的地址赋给cur指向的当前结点的next指针,让它指向前一结点,然后三个指针都向后移动一位,不断循环至cur指向NULL。反转后的新链表的头结点由prev指向,返回prev即可。
image.png
代码实现

struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode* prev = NULL;
    struct ListNode* cur = head;
    struct ListNode* next = NULL;

    while(cur)
    {
        next = cur->next;
        cur->next = prev;
        prev = cur;
        cur = next;
    }
    return prev;
}

【C语言刷题】合并两个有序链表&反转链表_第4张图片

你可能感兴趣的:(C语言刷题,c语言,数据结构,学习,链表)