前言:致力于转行的在读建筑硕士,在代码随想录及csdn见证自己在c语言道路上的成长,每一道题目尽可能通过一下顺序:自我编写-问题分析-学习代码-改进方案-知识总结~
题目:力扣203 移除链表元素
https://leetcode.cn/problems/remove-linked-list-elements/submissions/423873813/
方法一:不设置虚拟头节点
一、独立解题
1.1 解题思路
1)判断该链表是否为空链表,如果是,返回NULL
2)创建一个结构体指针cur,指向head
3)构建循环,当cur存在下一个节点时,判断下一个节点是否为val值,如果是,将当前节点的next指向下下个节点;如果不是,将当前指针指向下一个节点。
4)经过上述操作,还剩下一个首元节点没有进行判断。进而判断首元节点是否为val,如果是则将head指向head->next,即NULL。
1.2 要点记录
1)当移除一个不是头节点的元素时,涉及到三个元素:指针当前指向的位置、下一个位置的元素及下下个位置的元素,如图所示:
相当于删除的是cur指针指向的下一个元素,这是因为单向链表无法找到指针的上一个元素。
2)关于为什么不处理尾节点?
while(cur->next) 当前指针是否有下一个节点进行判断,即相当于判断当前节点是否为尾部节点。
1.3 代码实现
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val){
if(!head) return NULL;
struct ListNode* cur = head;
while(cur->next){
if(cur->next->val == val){
cur->next = cur->next->next;
}
else{
cur = cur->next;
}
}
if(head->val == val) head = head->next;
return head;
}
1.4 代码效果
1.5 存在问题
1) 未考虑内存释放的问题
2) 未能实现动态删除头节点
二、学习过程
2.1参考答案
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* temp;
// 当头结点存在并且头结点的值等于val时
while(head && head->val == val) {
temp = head;
// 将新的头结点设置为head->next并删除原来的头结点
head = head->next;
free(temp);
}
struct ListNode *cur = head;
// 当cur存在并且cur->next存在时
// 此解法需要判断cur存在因为cur指向head。若head本身为NULL或者原链表中元素都为val的话,cur也会为NULL
while(cur && (temp = cur->next)) {
// 若cur->next的值等于val
if(temp->val == val) {
// 将cur->next设置为cur->next->next并删除cur->next
cur->next = temp->next;
free(temp);
}
// 若cur->next不等于val,则将cur后移一位
else
cur = cur->next;
}
// 返回头结点
return head;
}
2.2 对比反思
1)关于while(head&&head->val == val)
不可以直接写while(head->val == val) 或者是(head->next),个人理解:如果当前头节点已经指向NULL,就不能对NULL进行val以及next操作;
按照编程语言的逻辑顺序,while(head&&head->val == val)中如果head为空,语句值返回0,并不会运行至下一个语句。
一定要先判断当前节点是否存在
2) 释放内存
注意需要通过设置临时指针变量,将cur指针指向正确位置后,再通过临时指针将要删除的节点进行内存释放。
三、总结反思
3.1 代码修改
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* tmp;
while(head&&head->val == val){
tmp = head;
head = head->next;
free(tmp);
}
struct ListNode* cur = head;
while(cur && cur->next){
if(cur->next->val == val){
tmp = cur->next;
cur->next = cur->next->next;
free(tmp);
}
else{
cur = cur->next;
}
}
return head;
}
3.2 细节总结
1)有指向的指针被释放后不能再进行取值或者再指向下一个操作,不能写成如下代码:
因为如果头节点被删除,cur指针就变成了NULL
注意定义变量的位置,防止这样的现象产生
后记:“慢也好,步子小也好,是在往前走就好了”