一:题目
二:思路讲解
方法一:
1:创建两个指针prev和cur,初识位置cur为head,prev为NULL,然后两个指针往后移动开始去寻找与val值吻合的节点,最后找到节点的时候,cur指向该节点,prev指向该节点的前一个节点,现在我们的目的是要删除这个cur指向的节点,让cur去指向该节点的下一个节点!
2:所以我们先将prev的next修改为该节点的下一个节点,将该节点的前后两点链接起来(prev->next = cur ->next)然后再让cur指向该节点的后一个节点(cur=prev->next )。
第一步:初始状态:
第二步:找到val值吻合的时候:
第三步: 先将prev的next修改为该节点的下一个节点,将该节点的前后两点链接起来(prev->next = cur ->next)
第四步: 然后再让cur指向该节点的后一个节点(cur=prev->next )。
这样就成功的删除了一个与val值吻合节点。
如果你疑问为什么不直接cur=cur->next,也就是直接让cur指向了该节点的下一个节点,那是因为我们需要释放掉该节点。而该节点是cur指向的,我们free(cur)的这一步,是放在第三步和第四步之间,free(cur)不会产生任何影响,如果直接cur=cur->next,那不管是在这一步之前还是之后free(cur),都会对cur产生影响,从而导致答案错误。
特殊情况:第一个或者前几个一直val值都吻合
第一步:初始状态:
这种情况,我们对prev的操作,会变成对空指针的解引用,这是错误的!
解决方法:寻找一个新的头,也就是让上面的链表变成下面:
这样又可以按照之前的方法做下去了。
代码展示:
由图可知: 判断特殊情况的if有两种写法,皆可。
方法二:
遍历原链表,把不是val的节点尾插到新链表。
1:首先需要一个cur初始为head,一个newhead(NULL),一个tail(NULL)来保存节点去进行尾插,这两个一开始都是NULL,因为可能链表是一个空链表,这样直接返回newhead就好。
2:发现与val值吻合的节点,先用一个指针del去保存这个节点,然后直接让cur指向该节点的下一个节点,然后free掉该节点,(free(del))。
3:发现与val值 不 吻合的节点,就进行尾插,尾插有两种情况,一种是第一次尾插,一种是不是第一次尾插。
第一次尾插:tail为null,要将cur赋值给newhead和tail,赋值给newhead就让其指向了第一个尾插的节点,这样newhead就是新链表的头指针了,赋值给tail是因为,tail要指向新链表的尾节点,tail会与cur进行新的尾节点的插入等工作。
不是第一次尾插:即tail不为null,先尾插,让tail指向的节点去链接到新的尾插节点(tail->next=cur),再移动tail,再让tail去指向新的尾插节点(tail=tail->next)。
第一步:发现val值吻合的节点,先用一个指针del去保存这个节点,然后直接让cur指向该节点的下一个节点,然后free掉该节点,(free(del))。
第二步:发现与val值 不 吻合的节点的第一次尾插
tail为null,要将cur赋值给newhead和tail
第三步:不是第一次的尾插
即tail不为null,先尾插,让tail指向的节点去链接到新的尾插节点(tail->next=cur)
再移动tail,再让tail去指向新的尾插节点(tail=tail->next)。
代码展示:
注意:
尾插的最后一个节点的next没有置空,所以我们在最后将tail->next=NULL,但是在这之前,我们得先判断tail是否为空,因为可能这个链表是个空链表或者全为val,这样才能避免对tail(NULL)的解引用。这一步不能在尾插的else里面进行,因为下一次的尾节点的插入会需要对tail进行解引用,这样会造成对NULL 的解引用! 所以在新链表完全形成之后,再去进行最为正确!