公主请阅
- [1. 移除链表元素](#1. 移除链表元素)
-
- [1. 题目说明](#1. 题目说明)
-
- [示例 1](#示例 1)
- [示例 2](#示例 2)
- [示例 3](#示例 3)
- [1.2 题目分析](#1.2 题目分析)
- [1.3 代码部分](#1.3 代码部分)
- [1.4 代码解析](#1.4 代码解析)
- [2. 反转链表](#2. 反转链表)
-
- [2. 1题目说明](#2. 1题目说明)
-
- [示例 1](#示例 1)
- [示例 2](#示例 2)
- [示例 3](#示例 3)
- [2.2 题目分析](#2.2 题目分析)
- [2.3 代码部分](#2.3 代码部分)
- [2.4 代码分析](#2.4 代码分析)
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 代码部分
C
/**
* 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
就是我们所说的哨兵位,用来占位子的
然后我们的tmp
的next
指针就指向我们原先的头结点了
然后我们再创建两个指针:
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 代码部分
C
/**
* 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
就变成了新的头结点了
我们将这个节点返回操作就行了