【问题标题】:Node deletion given a string input给定字符串输入的节点删除
【发布时间】:2020-03-09 07:28:34
【问题描述】:

我是新来的。我需要向大家询问有关链表的问题,特别是关于从给定字符串输入的任何位置删除节点的问题。我编写的这段代码据说可以完成任务......

void popMiddle(struct data **head, struct data **tail, char name[])
{
    if(*head == NULL)
    {
        printf("No Data to Delete\n");
    }

    else if(*head == *tail)
    {
        if (strcmp((*head)->name, name)==0)
        {
            free(*head);
            *head = *tail = NULL;
        }

        else
        {
            printf("No Data to Delete\n");
        }
    }

    else if (strcmp((*head)->name, name)==0)
    {
        struct data *curr = *head;
        *head = (*head)->next;
        free(curr);
        curr = NULL;
    }
    else
    {
        struct data *curr1 = *head;
        struct data *curr2;

        while (strcmp(curr1->next->name, name)!=0 && curr1 !=NULL)
        {

            printf("%d\n", curr1);
            curr1 = curr1->next;
        }

        if ( curr1->next != *tail )
        {
            curr2 = curr1->next;
            curr1->next = curr2->next;
            free(curr2);
            curr2 = NULL;

        }

        else if (curr1->next == *tail)
        {
            free(*tail);
            *tail = curr1;          
            (*tail)->next= NULL;
        }

        else  
        {
            printf("No Data to Delete\n");
        }
    }

}

这是我一直在使用的链接列表:

莎拉->约翰->戈登

我想删除一个包含“Jack”的节点。但是,如您所知,它不存在于链表中。因此,输出应该是“没有要删除的数据”。不幸的是,控制台不会打印任何东西...我怀疑这是循环。但我需要知道它哪里出错了...谢谢您的关注。

【问题讨论】:

  • 我需要知道如何确保代码遍历每个节点,同时将其与字符串输入进行比较。我很乐意弄清楚代码将如何到达else 子句。

标签: c linked-list


【解决方案1】:

你的程序很可能崩溃,这是因为循环

while (strcmp(curr1->next->name, name)!=0 && curr1 !=NULL)

这里有两个错误:

  1. 进行比较的顺序。逻辑 AND 运算符 && 将始终首先计算左侧,这意味着当指针 curr1NULL 时,您将取消引用指针 curr1。您需要更改两次比较的顺序以首先检查curr1 != NULL

  2. 第二个问题是你不检查curr1->next是否为空指针,这意味着已经在列表的最后一个节点上你将取消引用NULL指针。

我建议您将循环更改为 begin 并使用列表中的第二个节点,并在迭代期间检查“当前”节点:

struct data *curr1 = (*head)->next;

while (curr1 != NULL && strcmp(curr1->name, name) != 0)
{
    printf("%p\n", (void *) curr1);  // Changed to the format specifier %p, to print pointers
    curr1 = curr1->next;
}

如果未找到名称,则在此循环之后,curr1 将成为 NULL 指针。或者指向包含名称的节点的指针:

if (curr1 == NULL)
{
    printf("No Data to Delete\n");
}
else
{
    // Node found, remove it
}

现在来帮助您删除本身,为此您需要跟踪 previous 节点,这可以通过修改循环来完成,例如

struct data *curr = (*head)->next;
struct data *prev;
while (curr != NULL && strcmp(curr->name, name) != 0)
{
    prev = curr;  // Keep track of the previous node
    curr = curr->next;
}

现在很容易从列表中取消链接curr 节点:

prev->next = curr->next;

当然还要添加一个特殊情况,看看我们是否去掉了尾巴:

if (prev->next == NULL)
    *tail = prev;

进行更多更改后,您无需检查*head == *tailstrcmp((*head)->name, name)==0。这些情况实际上可以通过循环放入更通用的情况中。

把它们放在一起你的功能可能是这样的

void popMiddle(struct data **head, struct data **tail, char *name)
{
    struct data *curr = *head;  // Start iterating at the head
    struct data *prev = NULL;

    while (curr != NULL && strcmp(curr->name, name) != 0)
    {
        prev = curr;  // Keep track of the previous node
        curr = curr->next;
    }

    if (curr == NULL)
    {
        printf("No Data to Delete\n");
    }
    else
    {
        // Unlink node
        if (prev == NULL)
        {
            // Removed node was the head
            *head = curr->next;

            if (*head == NULL)
            {
                // We removed the last node in the list, it's now empty
                *tail = NULL;
            }
        }
        else
        {
            prev->next = curr->next;

            if (prev->next == NULL)
                *tail = prev;  // Removed the tail
        }

        // Free the found node
        free(curr);
    }
}

【讨论】:

  • 谢谢。我真的很喜欢你的洞察力!
猜你喜欢
  • 2022-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多