如何在c中删除链表中的节点
我需要做的是在c中实现一个函数来删除链表中的一个节点,使用strcmp的for和while循环。程序编译得很好,但循环从未停止过,有什么建议可以改进吗 结构如下:如何在c中删除链表中的节点,c,linked-list,C,Linked List,我需要做的是在c中实现一个函数来删除链表中的一个节点,使用strcmp的for和while循环。程序编译得很好,但循环从未停止过,有什么建议可以改进吗 结构如下: struct Test { char name[16]; int id; }; typedef struct Node { struct Test structure; struct Node * next; }TNode; typedef TNode * Nodo; 我写的函数是: void Delete(Nodo
struct Test
{
char name[16];
int id;
};
typedef struct Node
{
struct Test structure;
struct Node * next;
}TNode;
typedef TNode * Nodo;
我写的函数是:
void Delete(Nodo * pp)
{
Nodo i;
char temp[16], name[16];
printf("Insert the name to delete:");
scanf(" %s", name);
for(i = *pp; i->next != NULL ; i = i->next)
{
if(strcmp(i->structure.name, name) == 0)
{
while(i->next != NULL)
{
strcpy(temp,i->structure.name);
strcpy(i->structure.name, i->next->structure.name);
strcpy(i->next->structure.name, temp);
i = i->next;
}
}
}
}
更新:工作功能如下,感谢一些程序员的解释:
void Delete(Nodo * pp)
{
Nodo i, prev;
char name[16];
printf("Insert the name to delete:");
scanf(" %s", name);
//case for the first node
if(strcmp((*pp)->structure.name, name) == 0)
{
Nodo old = *pp;
*pp = (*pp)->next;
free(old);
return;
}
//loop to delete node inside list
for(prev = *pp, i = prev->next; i != NULL ; prev = i, i = i->next)
{
if(strcmp(i->structure.name, name) == 0)
{
prev->next = i->next;
free(i);
break;
}
}
}
[注意:这实际上并没有回答这个问题,但它告诉我们如何在单个链接列表中取消节点链接,IMO是OP面临的最大问题。]
假设您有以下列表
+---+ +---+ +---+ +---+
| A | -> | B | -> | c | -> | D |
+---+ +---+ +---+ +---+
这是不对的
相反,您使A
节点的next
指针指向C
,因此现在列表变为
+---+ +---+ +---+ +---+
| A | -\ | B | /-> | c | -> | D |
+---+ | +---+ | +---+ +---+
\-------/
取消节点链接的技巧是跟踪上一个节点。它可以这样实现:
// Special case: Removing the first node in the list
if (strcmp((*pp)->structure.name, name) == 0)
{
TNode *old = *pp; // Save a pointer to the node that should be removed
*pp = (*pp)->next; // Actually unlink the node from the list
free(old); // Free the memory of the old node
return;
}
TNode *prev; // To keep track of previous node
TNode *curr; // The "current" node
for (prev = *pp, curr = prev->next; curr != NULL; prev = curr, curr = curr->next)
{
if (strcmp(curr->structure.name, name) == 0)
{
// Found the node to remove
prev->next = curr->next; // Unlink the current node from the list
free(curr); // Free the node
break; // No need to iterate anymore
}
}
通过将prev
初始化为NULL
,并改为使用*pp
启动curr
,可以在循环内部解决第一个被删除节点的“特殊情况”。然后,您需要检查prev
是否为NULL
,或者是否不在循环中的if
中
代码看起来可能更多,可能有更多的行(即使删除了部分或全部空行),但我认为大多数人会说这更容易理解和了解发生了什么
当然,您还需要添加一个空列表检查,
pp
本身不为null(比如pp!=null&&*pp!=null
)。最好的做法是不要在typedef中隐藏指针。例如,您让我陷入了创建的混乱中…请注意,您的函数无法处理空列表,或仅包含一个节点的列表。如果复制后,我释放了最后一个节点,该怎么办?它将变成A-C-D-D,而不是A-C-D,如果我想删除,比如说C,首先列表将变成A-B-D-D,我释放最后一个节点,它将变成A-B-D。请告诉我这个推理是否有效。@St3veR0nix是的,它有效,但这比仅仅更改一个指针要复杂得多。而且可能会让许多程序员在看你的代码时感到困惑,因为在处理列表时更改指针是一种常见的方法。顺便说一句,我仍然很难找到答案,你能用一些代码回答吗?
+---+ +---+ +---+
| A | -> | c | -> | D |
+---+ +---+ +---+
// Special case: Removing the first node in the list
if (strcmp((*pp)->structure.name, name) == 0)
{
TNode *old = *pp; // Save a pointer to the node that should be removed
*pp = (*pp)->next; // Actually unlink the node from the list
free(old); // Free the memory of the old node
return;
}
TNode *prev; // To keep track of previous node
TNode *curr; // The "current" node
for (prev = *pp, curr = prev->next; curr != NULL; prev = curr, curr = curr->next)
{
if (strcmp(curr->structure.name, name) == 0)
{
// Found the node to remove
prev->next = curr->next; // Unlink the current node from the list
free(curr); // Free the node
break; // No need to iterate anymore
}
}