轻触节点,链表里的悄然邂逅

发布于:2024-10-18 ⋅ 阅读:(5) ⋅ 点赞:(0)

在这里插入图片描述

1. 移除链表元素

在这里插入图片描述
题目传送门


1. 题目说明

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1

在这里插入图片描述

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]


示例 2

输入:head = [], val = 1
输出:[]


示例 3

输入:head = [7,7,7,7], val = 7
输出:[]


1.2 题目分析

题目给了我们一个链表,要求说让我们将值等于val的链表删除,并且返回新的头结点
那么这个题我们该怎么进行解决呢?
我的想法是:我们可以通过设置一个哨兵位然后利用双指针进行链表的遍历,然后我们的两个指针如果在遍历过程中遇到了满足条件的节点的话,我们直接忽略了,将这个节点的前一个节点的next的指针进行改变,指向这个节点的下一个节点,通过这种方法我们间接的将这个节点删除了


1.3 代码部分

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeElements(struct ListNode* head, int val)
{
    //创建一个哨兵节点(tmp),哨兵节点的next指针指向头结点
    struct ListNode*tmp=(struct ListNode*)malloc(sizeof(struct ListNode));
    tmp->next=head;

    //双指针
    struct ListNode*prev=tmp;//慢指针--当前节点的前一个节点,从哨兵卫开始
    struct ListNode*cur=head;//快指针遍历链表的当前节点,从头结点开始

    //遍历整个链表
    while(cur!=NULL)
    {
        if(cur->val==val)//如果当前节点的值等于val的话,那么我们就跳过当前节点
        {
            prev->next=cur->next;//当前遍历的节点的前一个节点的next将会直接指向当前节点的下个节点
            //就是说直接将当前节点忽略掉了
        }
        else//当前节点的值不等于val,那么我们继续往后移动
        {
            //移动prev
            prev=cur;
        }
        cur=cur->next;
    }
    //循环结束了,那么这个满足条件的节点就删除了

    //重新定义头结点,将哨兵卫忽略就行了
    struct ListNode*newHead=tmp->next;//用指针将头节点进行定义
    free(tmp);//释放哨兵卫
    return newHead;//返回我们之前保存的头结点的指针
}


1.4 代码解析

我们先利用malloc动态申请一个节点赋值给tmp,这个tmp就是我们所说的哨兵位,用来占位子的
然后我们的tmpnext指针就指向我们原先的头结点了
然后我们再创建两个指针:

  • prev—慢指针,当前节点的前一个节点,从哨兵位开始
  • cur—当前节点,从头结点开始

说明:我们的这个哨兵位仅仅是一个空节点,并不存在实际的数据的,我们创建出来只是用来占位子的

然后我们就可以进行遍历整个链表的操作了
遍历的循环条件是我们的当前节点cur不是空,就是只要到了尾节点我们就停下来了
我们在循环里面进行判断,如果当前节点的val满足条件的话,我们让这个节点的前一个节点指向这个节点的下一个节点,来达到间接删除当前的节点的作用
但是如果当前节点不满足的话我们就让prev这个指针赋值为cur
然后在这个while循环的结束位置,我们就进行移动的操作,进行链表节点的遍历操作
等循环结束了,我们这个链表中满足条件的val就间接被删除了
然后我们再重新定义头结点
头结点就是我们哨兵位的next指针指向的节点,这个时候我们的哨兵位的作用就发挥出来了
然后我们将哨兵位释放掉就行了,这个题就结束了


2. 反转链表

在这里插入图片描述
题目传送门


2. 1题目说明

这是 LeetCode 第 206 题:反转链表 的问题描述:

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

示例 1

  • 输入: head = [1,2,3,4,5]
  • 输出: [5,4,3,2,1]

示例 2

  • 输入: head = [1,2]
  • 输出: [2,1]

示例 3

  • 输入: head = []
  • 输出: []

限制条件

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

2.2 题目分析

逆转链表顾名思义就是链表逆置
假设当前链表是1->2->3->4->5
逆置过后就是这个样子的5->4->3->2->1

那么我们怎么进行下面的操作呢?
我们还是使用双指针进行链表的遍历,关于这个逆置的操作我们在遍历的时候同时进行
同样是定义两个指针,然后在遍历的时候将当前的指向指向上一个节点,然后进行当前节点的改变,改变相邻两个节点的指针,随手遍历结束,我们的尾节点就变成了头结点,最后我们直接将头结点进行返回就行了
请看下面代码部分


2.3 代码部分

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode*prev=NULL;//定义当前节点的前一个节点
    //因为反转后原始链表的头节点将成为新链表的尾节点,它的下一个节点应该指向 NULL。
    struct ListNode*cur=head;//用于遍历链表,从头结点开始

    while(cur!=NULL)//遍历链表
    {
        struct ListNode*nexttmp=cur->next;//保存当前节点的下一个节点

        //下面的两个代码就是对当前节点和当前节点的前面进行操作,进行指针逆转操作
        cur->next=prev;//当前节点的指针反转了,指向了前一个节点
        prev=cur;//当前节点变成了前一个节点了

        cur=nexttmp;//将cur移动到下一个节点的位置
    }
    //出了循环之后这个逆转操作就完成了
    return prev;//反转后的链表prev成为了新的头节点了
}

2.4 代码分析

我们先定义一个指针prev指向前一个节点,但是初始化我们设置为NULL,然后我们再定义一个指针cur指向当前的头节点head
然后我们使用while循环进行遍历链表,结束条件是遍历到尾节点就停止
我们在循环里面先定义一个指针nexttmp将当前节点的下个节点进行保存的操作
然后下面就是我们三个节点直接的指向变换了
我们让当前节点cur的下一个节点的指针next指向我们的前一个节点prev,然后我们让这个前一个节点prev变成我们的当前节点cur进行下一组相邻节点的逆置操作
然后我们让当前的cur变成我们当时保存的下一个节点的指针,我们现在对这两个节点进行逆置操作
随着循环结束,我们的最后prev就变成了新的头结点了
我们将这个节点返回操作就行了