删除未排序链表中的所有重复节点

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 地址进行任何不必要的更改吗? 这是我对弗拉德回答的理解。

以上是关于删除未排序链表中的所有重复节点的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode83. 删除排序链表中的重复元素

Leetcode删除排序链表中的重复元素

删除排序链表中的重复元素--链表

《LeetCode之每日一题》:99.删除排序链表中的重复元素 II

83. 删除排序链表中的重复元素

迭代LeetCode 82. 删除排序链表中的重复元素 II