方法一:迭代(无虚拟头结点)
自己写的错误版
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* p = head->next;
struct ListNode* pre = head;
while(p != NULL){
if(p->val == val){
pre->next = p->next;
free(p);
p = pre->next;
} else{
pre = p;
p = p->next;
}
}
return head;
}
出错原因:没有判断头节点是否为待删除的节点
注意点:
在寻找值为给定值的节点时,需要先判断节点是否为空节点;
/* 没有判断 head 节点是否为空节点 */
if (head->val == val) {
...........
}
改为如下:
if (head != NULL && head->val == val) {
head = head->next;
}
执行上面的操作之后,把值等于给定值的头节点删除了,但很有可能新的头节点(原链表的第二个节点)的值还跟 val 相等,所以 if 应当改为 while,循环删除。
while (head != NULL && head->val == val) {
head = head->next;
}
链表的所有节点的值可能都为 val,因此删除完之后需要再判断链表是否为空。
while (head != NULL && head->val == val) {
head = head->next;
}
/* 判断此时链表是否为空,为空的话直接返回 */
if (head == NULL) {
return NULL;
}
正确代码:
struct ListNode* removeElements(struct ListNode* head, int val){
while (head != NULL && head->val == val) {
head = head->next;
}
if (head == NULL) {
return NULL;
}
struct ListNode* p = head->next;
struct ListNode* pre = head;
while(p != NULL){
if(p->val == val){
pre->next = p->next;
free(p);
p = pre->next;
} else{
pre = p;
p = p->next;
}
}
return head;
}
方法二:虚拟头节点
通过在头节点前增加虚拟头节点,这样头节点就成了普通节点,不需要单独拎出来考虑,但是在返回的时候,返回的是虚拟头节点的下一节点而不是虚拟头节点。
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* pre = malloc(sizeof(struct ListNode));
pre->next = head;
struct ListNode* p = pre;
//p作为中间变量
while(p->next != NULL){
if(p->next->val == val){
p->next = p->next->next;
//此处不会有free(p);之类的
} else{
p = p->next;
}
}
return pre->next; //return一个不变的量
}
方法三:递归
struct ListNode* removeElements(struct ListNode* head, int val){
if(head == NULL){
return head;
}
head->next = removeElements(head->next, val);
return head->val == val ? head->next : head;
}