思路一:不存在哨兵头结点时
该题为链表中数据的删除,即将符合条件的节点释放掉,将剩余节点重新连接起来,因为不只是将需要删除的节点释放掉。而且要将该节点的前后两个节点连接起来,因此不能单纯地找该节点,同时应该找前一个节点,按照以前的思路,定义一个指针pre,在cur依次向后判断的时候,跟随充当目标节点的前一个节点
这样依次向后排查,直到cur指向空指针停止
但是忽略了一个问题,万一第一个节点就需要删除
如图,若是第一个节点就需要删除,则将cur释放之后,在pre与next连接的过程中,因为pre此时是空指针,无法将next储存到pre当中去,此时就要另外考虑思路
当第一个节点需要删除,可以在该节点删除后把后一个节点当作头节点,再依次进行筛选
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* pre=NULL;
struct ListNode* cur=head;
while(cur!=NULL)
{
struct ListNode* next=cur->next;
if(cur->val==val)
{
if(pre==NULL)//当第一个节点需要删除,改变头节点
{
free(cur);
head=next;
cur=next;
}
else
{
pre->next=next;
free(cur);
cur=next;
}
}
else
{
pre=cur;
cur=cur->next;
}//如果不需要删除,则依次向后排查
}
return head;
}
注意:
1.因为最后要再次返回头节点,在头节点需要删除的这种情况下,记得把下一个节点传到head中
2.在利用指针的时候要注意函数的返回值类型,当函数是void类型的时候,对传进来的地址要进行改变,则需要二级指针,否则就是单纯的值传递,函数外无法改变,如果像本题要返回一个地址,这不需要二级指针
3.删除一个节点不是单纯地将前后两个节点连起来,要将该节点释放掉,然后指针cur指向下一个节点
思路二:含有哨兵头节点
因为要考虑第一个节点是否删除的问题,其实我们可以自己定义一个哨兵头节点,相当于链表加了一个首相,原先的头节点就变成了第二个,因此只需要依次向后排查即可
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* guardhead=(struct ListNode*)malloc(sizeof(struct ListNode));
guardhead->next=head;
struct ListNode* pre=NULL;
struct ListNode* cur=guardhead;
while(cur!=NULL)
{
struct ListNode* next=cur->next;
if(cur->val==val)
{
pre->next=next;
free(cur);
cur=next;
}
else
{
pre=cur;
cur=cur->next;
}
}
head=guardhead->next;
free(guardhead);
return head;
}
注意:
1.因为guardhead是新开辟出来的,最后返回的时候不能单纯地返回guardhead->next,否则会出现内存泄露的问题,最后要把guardhead释放掉
2.到最后连表示已经删除完了的,因此直接将guardhead->next赋给head即可