提问人:iskander 提问时间:9/19/2023 最后编辑:iskander 更新时间:9/19/2023 访问量:96
删除链表中的节点
Delete node in the linked list
问:
给定链表的头部和一个整数,删除链表中所有具有 的节点,并返回新的头部。val
Node.val == val
这是我的尝试
struct ListNode *removeElements(struct ListNode *head, int val) {
struct ListNode *tmp, *prev;
if (head == NULL)
return head;
for (tmp = head, prev = NULL; tmp != NULL; prev = tmp, tmp = tmp->next)
if (tmp->val == val) {
prev->next = tmp->next;
free(tmp);
}
return head;
}
但我遇到了分段错误。问题似乎很容易,但我不明白我的错误在哪里。
答:
2赞
chqrlie
9/19/2023
#1
如果第一个节点的值为 ,则该语句将导致分段错误,因为该指针为 null。使用您的方法,您必须对列表的开头进行特殊情况:val
prev->next = tmp->next;
prev
struct ListNode *removeElements(struct ListNode *head, int val) {
while (head != NULL && head->val == val) {
struct ListNode *tmp = head;
head = head->next;
free(tmp);
}
if (head != NULL) {
for (struct ListNode *prev = head, *cur = head->next; cur != NULL;) {
if (cur->val == val) {
struct ListNode *tmp = cur;
prev->next = cur = cur->next;
free(tmp);
} else {
prev = cur;
cur = cur->next;
}
}
}
return head;
}
下面是一个使用双指针的更简单的解决方案:
struct ListNode *removeElements(struct ListNode *head, int val) {
struct ListNode **pp = &head;
struct ListNode *tmp;
while ((tmp = *pp) != NULL) {
if (tmp->val == val) {
*pp = tmp->next;
free(tmp);
} else {
pp = &tmp->next;
}
}
return head;
}
1赞
Vlad from Moscow
9/19/2023
#2
这个 for 循环
for (tmp = head, prev = NULL; tmp != NULL; prev = tmp, tmp = tmp->next)
if (tmp->val == val) {
prev->next = tmp->next;
free(tmp);
}
有三个问题。
主要问题是循环不会改变指针(变量)本身。head
因此,如果头节点的数据成员等于变量的值,则指针的值不会更改。val
val
head
第二个问题是,最初指针等于 。因此,如果指针指向的节点将被删除,则在此语句中使用空 ponter 来访问内存prev
NULL
head
prev->next = tmp->next;
这会导致未定义的行为。
最后第三个问题是可以使用已经删除的节点
free(tmp);
在 for 循环的表达式中
tmp = tmp->next
此外,在这种情况下,指针被设置为指向已删除节点的指针prev
tmp
prev = tmp
可以实施两种方法。
第一种是首先检查指针所指向的节点。head
给你。
struct ListNode * removeElements( struct ListNode *head, int val )
{
if ( head != NULL )
{
while ( head->val == val )
{
struct ListNode *tmp = head;
head = head->next;
free( tmp );
}
if ( head != NULL )
{
for ( ListNode *current = head; current->next != NULL; )
{
if ( current->next->val == val )
{
ListNode *tmp = current->next;
current->next = current->next->next;
free( tmp );
}
else
{
current = current->next;
}
}
}
}
return head;
}
第二种方法是通过指向指针的指针来引用列表中的指针。
struct ListNode * removeElements( struct ListNode *head, int val )
{
for ( struct ListNode **current = &head; *current != NULL; )
{
if ( ( *current )->val == val )
{
struct ListNode *tmp = *current;
*current = ( *current )->next;
free( tmp );
}
else
{
current = &( *current )->next;
}
}
return head;
}
请注意,应始终在使用变量的最小范围内声明变量。
评论
free(tmp)
tmp = tmp->next
prev->next = ...
prev
NULL