【问题标题】: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

标签: c struct free singly-linked-list function-definition


【解决方案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 地址进行任何不必要的更改吗?
  • 这是我对弗拉德回答的理解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
  • 2014-08-15
  • 2013-07-12
  • 2013-12-14
相关资源
最近更新 更多