删除未排序链表中的所有重复节点
Posted
技术标签:
【中文标题】删除未排序链表中的所有重复节点【英文标题】:delete all duplicated nodes in unsorted linked list 【发布时间】:2022-01-07 07:11:01 【问题描述】:我的代码的主要目的是从用户那里获取数据,然后搜索单链表找到目标,然后删除所有等于目标的节点。 这也是基础单链表:
typedef struct Node
int data;
struct Node *next;
no;
输入: 1, 2, 3, 2, 5 --> to delete= 2
所以新的链表是:1,3,5
void* toDElduplicatedlinkedlist (no* firstNode, int target)
no* current = firstNode;
no* ptemp;
while ( NULL != current->next)
if (firstNode->data == target)
current = firstNode->next;
free(firstNode);
else if (current->next->data == target)
ptemp = current->next;
current->next= current->next->next;
free(ptemp);
current = current->next;
这是我写的删除函数。
它适用于链接列表中间的目标项目,但是当列表头部的firstNode
是目标时,它要么不删除它,要么丢失头地址,我尝试了很多方法来保存列表的头部,使其不会松动。
它也不适用于最后一个节点为目标的情况。
我一直在努力解决这个问题,但我无法解决它,所以如果有人帮助我解决这个问题,我会很高兴和感激。
【问题讨论】:
您在循环的每次迭代中检查firstNode
值,即使在第一个节点可能被释放之后也是如此。您可能会遇到释放后使用错误。莫斯科的回答中@Vlad 中还指定了其他设计缺陷
哦,我明白了。谢谢@MichaelSohnen
【参考方案1】:
需要一个指向指针的指针来修改给定函数的头节点,并且应该只在当前不为空时循环。
void* toDEduplicatedlinkedlist(no** firstNode, int target)
no* current = *firstNode;
no* ptemp = *firstNode;
while (NULL != current)
no* temp = NULL;
if (current->data == target)
if (current == *firstNode)
*firstNode = current->next;
else
ptemp->next = current->next;
temp = current;
else
ptemp = current;
current = current->next;
if(temp != NULL) free(temp);
return *firstNode;
【讨论】:
感谢您的回复和帮助。我现在明白了。 @Rosha.R 提供的代码不正确并且具有未定义的行为。 @VladfromMoscow 我现在看到了它是如何出错的。谢谢你的提醒。 @VladfromMoscow 我明白了,我在推进它之前释放了电流,我更新了正确的答案。【参考方案2】:对于初学者来说,虽然它的返回类型是void *
,但该函数什么也不返回。
这个while循环
while ( NULL != current->next)
如果为空列表调用函数,则可以调用未定义的行为。
当列表只包含一个节点时,也会跳过while循环。
或者例如,如果第一个节点包含一个等于参数目标的值,那么在循环的第一次迭代中,指向的节点将被释放。但是,在循环的下一次迭代中,您将再次检查已删除的节点
if (firstNode->data == target)
current = firstNode->next;
free(firstNode);
另一个调用未定义的行为。
函数可以通过以下方式声明和定义
void toDElduplicatedlinkedlist( no **firstNode, int target )
while ( *firstNode )
if ( ( *firstNode )->data == target )
no *tmp = *firstNode;
*firstNode = ( *firstNode )->next;
free( tmp );
else
firstNode = &( *firstNode )->next;
如果你在函数的调用者中有
no *firstNode;
然后调用函数就像
toDElduplicatedlinkedlist( &firstNode, target );
即指向链表第一个节点的指针是通过引用传递的。
定义函数的另一种方式如下
no * toDElduplicatedlinkedlist( no *firstNode, int target )
while ( firstNode && firstNode->data == target )
no *tmp = firstNode;
firstNode = firstNode->next;
free( tmp );
if ( firstNode != NULL )
for ( no *current = firstNode; current->next != NULL; )
if ( current->next->data == target )
no *tmp = current->next;
current->next = current->next->next;
free( tmp );
else
current = current->next;
return firstNode;
在这种情况下,函数被称为
firstNode = toDElduplicatedlinkedlist( firstNode, target );
最后也可以这样定义函数
no * toDElduplicatedlinkedlist( no *firstNode, int target )
for ( no **current = &firstNode; *current; )
if ( ( *current )->data == target )
no *tmp = *current;
*current = ( *current )->next;
free( tmp );
else
current = &( *current )->next;
return firstNode;
并以与上图相同的方式调用即
firstNode = toDElduplicatedlinkedlist( firstNode, target );
【讨论】:
我有点疑惑,这段代码怎么不会不小心把列表的头部移到了尾部呢?为什么我们不需要保存firstNode
的副本?这是通过额外的间接级别解决的吗?
@MichaelSohnen 它是指向被移动到列表尾部的指针的指针。
我明白了。谢谢!
感谢您的回复。这里我有个问题,no **firstNode
是指向我们单链表的第一个Node的指针吗?是因为我们避免对主要firstNode
地址进行任何不必要的更改吗?
这是我对弗拉德回答的理解。以上是关于删除未排序链表中的所有重复节点的主要内容,如果未能解决你的问题,请参考以下文章