【问题标题】:Remove all nodes with the same occurrences of the given string from doubly linked list从双向链表中删除所有与给定字符串出现相同的节点
【发布时间】:2021-02-18 12:51:42
【问题描述】:

我正在尝试删除给定字符串的所有出现。此代码删除一个节点,但所有其他节点都保留。我试图将它包装在一个while循环中,但仍然没有效果。

我也想知道,是否可以删除 struct 参数并仍然让它发生。我试图删除它并修改了代码,但我得到一个分段错误。感谢您提前回答。

void deleteNode(struct node** head, char* searchName) {

        struct node* current;
        for(current=*head; current; current = current->next){
            if (!strcmp(current->name, searchName))
            {
            if (current->next)
                current->next->prev = current->next;
                if (current->prev)
                current->prev->next = current->prev;
                if (current == *head)
                *head = current->next;
                current->prev = NULL;
                current->next = NULL;
                free(current);
                return;
                }
            }
    }

【问题讨论】:

  • 你们有 Valgrind 吗?如果是这样,请使用它。你有代码来打印你的列表吗?如果是这样,您可以使用它在适当的阶段检查您的结果。 return 是您最多只删除一个节点的原因。在释放内存之前对current->prevcurrent->next 的分配是多余的(无害,但也没有必要)。

标签: c pointers linked-list doubly-linked-list function-definition


【解决方案1】:

你的功能是错误的。例如这个 if 语句

 if (current->next)
            current->next->prev = current->next;

应该像这样重写

 if (current->next)
            current->next->prev = current->prev;
                                           ^^^^

函数可以通过以下方式声明和定义

void deleteNode( struct node **head, const char *searchName )
{
    while ( *head )
    {
        if ( strcmp( ( *head )->name, searchName ) == 0 )
        {
            struct node *current = *head;
            if ( current->next ) current->next->prev = current->prev;
            *head = current->next;
            
            free( current );
        }
        else
        {
            head = &( *head )->next;
        }
    }
}

注意,如果结构体struct node的数据成员name指向一个动态分配的存储字符串的内存,那么在为上述函数中的指针current调用函数free之前,你必须释放为字符串分配的内存。那就是你需要再调用一个函数freelike

free( current->name );
free( current );

如果你有一个指向头节点的全局指针,例如head,那么该函数可以通过以下方式定义

void deleteNode( const char *searchName )
{
    struct node **head_ref = &head;

    while ( *head_ref )
    {
        if ( strcmp( ( *head_ref )->name, searchName ) == 0 )
        {
            struct node *current = *head_ref;
            if ( current->next ) current->next->prev = current->prev;
            *head_ref = current->next;
            
            free( current );
        }
        else
        {
            head_ref = &( *head_ref )->next;
        }
    }
}

【讨论】:

  • 非常感谢来自莫斯科的@Vlad。如果没有参数中给出的节点,请问您将如何做到这一点?
  • @NotsureAnymore 只有当指向头节点的指针是全局变量时才可以这样做。但这样的做法并不好。指向项目中头节点的指针是全局的吗?
  • 啊,我明白了,非常感谢!我有另一个函数,但它仅用于返回具有给定字符串的节点的索引。它总是跳转到列表中存在元素dosent。我要发在这里吗?还是我应该创建一个新问题?来自莫斯科的@Vlad
  • @NotsureAnymore 最好再问一个新问题。
  • 我看到您的电子邮件已放入您的个人资料中,我可以联系您吗 :D ?来自莫斯科的@弗拉德
【解决方案2】:

return 语句将在第一次命中后结束函数。此外,序列current->next = NULL; free(current); current = current->next 将在释放内存后访问内存,并将 current 设置为 NULL。您可能需要在循环内更新current 并使用一个额外的节点指针变量进行删除。

void deleteNode(struct node** head, char* searchName)
{
    struct node* current;
    struct node* to_delete;
    for(current=*head; current;)
    {
        if (!strcmp(current->name, searchName))
        {
            to_delete = current;
            current = current->next;
            if (current) {
                current->prev = to_delete->prev;
            }
            if (to_delete->prev) {
                to_delete->prev->next = current;
            }
            if (to_delete == *head)
                *head = current;
            free(to_delete);
        } else {
            current = current->next;
        }
    }
}

【讨论】:

  • 关于循环重新初始化步骤访问被设置为 NULL 的已释放内存的要点。这无济于事!
  • 好的,我调整了断开连接位,现在怎么样?
  • 我也没有 :)
  • 谢谢你们!但我在收到退货部分的提示后马上就明白了! @JonathanLeffler。
  • 感谢@dratenik,我仍然想知道是否可以删除方法中的参数?`带有结构节点**头的那个。并且只通过 searchname
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多