C 从链接列表中搜索和删除
我对这个函数有困难。 该函数用于在链表中搜索学生并删除此节点,或者在未找到该学生时打印错误消息。以下代码无法正常工作,它将删除正在搜索的节点之后的下一个节点C 从链接列表中搜索和删除,c,linked-list,singly-linked-list,C,Linked List,Singly Linked List,我对这个函数有困难。 该函数用于在链表中搜索学生并删除此节点,或者在未找到该学生时打印错误消息。以下代码无法正常工作,它将删除正在搜索的节点之后的下一个节点 void vymazstudenta(STUDENT **head,const char *priezvisko) { STUDENT *traverse = *head; while(traverse!=NULL) { if(!strcmp(traverse->priezvisko,priez
void vymazstudenta(STUDENT **head,const char *priezvisko)
{
STUDENT *traverse = *head;
while(traverse!=NULL)
{
if(!strcmp(traverse->priezvisko,priezvisko))
{
STUDENT *hladany = traverse->next;
traverse->next = hladany->next;
free(hladany);
return;
}
traverse = traverse->next;
}
fprintf(stderr,"Student %s sa nenasiel.\n",priezvisko);
return;
}
当遍历列表时,您必须存储位于正在检查的节点之前的节点。我在下面的代码段中使用了名为previous的指针 当您找到匹配的节点时,您只需将前一个节点上的下一个节点设置为当前节点的下一个节点,这样列表将跳过要删除的节点。 然后可以释放匹配的节点 请注意,您应该处理这样一种特殊情况,即要删除的节点是头部的第一个节点 在下面的代码片段中,您可以在if-previous==NULL块中看到这一点——这是非常自解释的
void vymazstudenta(STUDENT **head,const char *priezvisko)
{
STUDENT *traverse = *head;
STUDENT *previous = NULL;
while( traverse != NULL )
{
if( strcmp(traverse->priezvisko,priezvisko) == 0 )
{
if( previous == NULL )
{
*head = traverse->next;
}
else
{
previous->next = traverse->next;
}
free( traverse );
return;
}
else
{
previous = traverse;
traverse = traverse->next;
}
}
fprintf(stderr,"Student %s sa nenasiel.\n",priezvisko);
return;
}
当遍历列表时,您必须存储位于正在检查的节点之前的节点。我在下面的代码段中使用了名为previous的指针 当您找到匹配的节点时,您只需将前一个节点上的下一个节点设置为当前节点的下一个节点,这样列表将跳过要删除的节点。 然后可以释放匹配的节点 请注意,您应该处理这样一种特殊情况,即要删除的节点是头部的第一个节点 在下面的代码片段中,您可以在if-previous==NULL块中看到这一点——这是非常自解释的
void vymazstudenta(STUDENT **head,const char *priezvisko)
{
STUDENT *traverse = *head;
STUDENT *previous = NULL;
while( traverse != NULL )
{
if( strcmp(traverse->priezvisko,priezvisko) == 0 )
{
if( previous == NULL )
{
*head = traverse->next;
}
else
{
previous->next = traverse->next;
}
free( traverse );
return;
}
else
{
previous = traverse;
traverse = traverse->next;
}
}
fprintf(stderr,"Student %s sa nenasiel.\n",priezvisko);
return;
}
您需要在遍历之前跟踪元素,以便可以将该元素的下一个指针更改为指向遍历之后的元素。然后你就可以自由穿越了 此外,您需要处理一个特殊情况。当匹配在*head元素上时。在这种情况下,您必须更新*head以获得新的列表头 比如:
void vymazstudenta(STUDENT **head,const char *priezvisko)
{
if (*head == NULL)
{
// empty list
return;
}
if(!strcmp(*head->priezvisko,priezvisko))
{
// Special case:
// Remove the *head element
STUDENT *hladany = *head; // Save a pointer to current head
*head = *head->next; // Update head
free(hladany); // Free the previous head
return;
}
STUDENT *traverse = *head->next;
STUDENT *previous = *head;
while(traverse!=NULL)
{
if(!strcmp(traverse->priezvisko,priezvisko))
{
previous->next = traverse->next; // Update previous to point
// to element after traverse.
free(traverse); // Now free traverse
return;
}
previous = traverse; // Move previous to next element
traverse = traverse->next; // Move traverse to next element
}
fprintf(stderr,"Student %s sa nenasiel.\n",priezvisko);
return;
}
您需要在遍历之前跟踪元素,以便可以将该元素的下一个指针更改为指向遍历之后的元素。然后你就可以自由穿越了 此外,您需要处理一个特殊情况。当匹配在*head元素上时。在这种情况下,您必须更新*head以获得新的列表头 比如:
void vymazstudenta(STUDENT **head,const char *priezvisko)
{
if (*head == NULL)
{
// empty list
return;
}
if(!strcmp(*head->priezvisko,priezvisko))
{
// Special case:
// Remove the *head element
STUDENT *hladany = *head; // Save a pointer to current head
*head = *head->next; // Update head
free(hladany); // Free the previous head
return;
}
STUDENT *traverse = *head->next;
STUDENT *previous = *head;
while(traverse!=NULL)
{
if(!strcmp(traverse->priezvisko,priezvisko))
{
previous->next = traverse->next; // Update previous to point
// to element after traverse.
free(traverse); // Now free traverse
return;
}
previous = traverse; // Move previous to next element
traverse = traverse->next; // Move traverse to next element
}
fprintf(stderr,"Student %s sa nenasiel.\n",priezvisko);
return;
}
该函数是错误的,至少因为它忽略了标头满足条件时的大小写 此外,还应将节点保留在已删除节点之前 该函数可以按以下方式显示
void vymazstudenta( STUDENT **head, const char *priezvisko )
{
STUDENT *tmp = NULL;
if ( *head != NULL )
{
if ( strcmp( head->priezvisko, priezvisko ) == 0 )
{
tmp = *head;
*head = ( *head )->next;
}
else
{
STUDENT *traverse = *head;
while( traverse->next != NULL && strcmp( traverse->next->priezvisko, priezvisko ) != 0 )
{
traverse = traverse->next;
}
if ( traverse->next != NULL )
{
tmp = traverse->next;
traverse->next = traverse->next->next;
}
}
}
if ( tmp != NULL )
{
free( tmp );
}
else
{
fprintf( stderr, "Student %s sa nenasiel.\n", priezvisko );
}
}
该函数是错误的,至少因为它忽略了标头满足条件时的大小写 此外,还应将节点保留在已删除节点之前 该函数可以按以下方式显示
void vymazstudenta( STUDENT **head, const char *priezvisko )
{
STUDENT *tmp = NULL;
if ( *head != NULL )
{
if ( strcmp( head->priezvisko, priezvisko ) == 0 )
{
tmp = *head;
*head = ( *head )->next;
}
else
{
STUDENT *traverse = *head;
while( traverse->next != NULL && strcmp( traverse->next->priezvisko, priezvisko ) != 0 )
{
traverse = traverse->next;
}
if ( traverse->next != NULL )
{
tmp = traverse->next;
traverse->next = traverse->next->next;
}
}
}
if ( tmp != NULL )
{
free( tmp );
}
else
{
fprintf( stderr, "Student %s sa nenasiel.\n", priezvisko );
}
}
这就是这段代码所做的。你需要修理它。提示:保存以前扫描的节点。如果在问题中说了,它将删除下一个节点。您正在保存对下一个节点的引用,然后将其释放:STUDENT*hladany=traverse->next。。。弗里赫拉丹;在没有malloc的情况下,为什么循环中有一个空闲节点?@LeeDanielCrocker假设每个节点都分配到其他地方。此函数只是删除一个节点。如果您只是利用已提供的指向指针的指针来遍历列表中的指针,这可能会变得更简单。根据推断,这意味着您也遍历了它们指向的节点。这就是这段代码所做的。你需要修理它。提示:保存以前扫描的节点。如果在问题中说了,它将删除下一个节点。您正在保存对下一个节点的引用,然后将其释放:STUDENT*hladany=traverse->next。。。弗里赫拉丹;在没有malloc的情况下,为什么循环中有一个空闲节点?@LeeDanielCrocker假设每个节点都分配到其他地方。此函数只是删除一个节点。如果您只是利用已提供的指向指针的指针来遍历列表中的指针,这可能会变得更简单。根据推断,这意味着您也遍历了它们指向的节点。或者,只需将提供给函数的指向指针的头指针用作双重用途,并消除这段代码中的一部分@WhozCraig我试图保持代码与OP发布的代码片段相似,以便让他更好地理解解决方案背后的逻辑。当然,您的方法要优雅得多。@4386427已修复。非常感谢。或者,只需将提供给函数的指向指针的头指针用作双重用途,并消除这段代码中的一部分@WhozCraig我试图保持代码与OP发布的代码片段相似,以便让他更好地理解解决方案背后的逻辑。当然,您的方法要优雅得多。@4386427已修复。非常感谢。