简体   繁体   English

从C中的列表中删除

[英]Deleting from a List in C

Basically I have to delete a certain item from a linked list. 基本上,我必须从链接列表中删除某个项目。 This code works: 此代码有效:

void delete_(Item client){
    link s=head,r;
    if(head->item==client){
        r=head;
        head=head->next;
        free(r);
    }
    else{
        while(s->next!=NULL){
            if(s->next->item==client){
                r=s->next;
                s->next=s->next->next;
                free(r);
            }
            else
                s=s->next;
        }
    }
}

Now I tried to reduce and compact the code using a for with 2 pointer but I can't figure out how to make it works. 现在,我尝试使用带有2指针的for来减少和压缩代码,但是我不知道如何使其工作。 Here's the code: 这是代码:

void delete_(Item client){
    link x,r,p;
    for(x=head;x!=NULL;p=x,x=x->next){
        if(x->item==client){
            r=x;
            p->next=x->next;
            free(r);
        }
    }
}

You can use for example the following appeoach 您可以使用例如以下方法

void delete( Item client )
{
    link current = head, previous = NULL;

    while ( current && current->item != client )
    {
        previous = current;
        current = current->next;
    }

    if ( current )
    {
        if ( !previous ) head = head->next;
        else previous->next = current->next;

        free( current );
    }
}

If you want to delete all nodes that have member item equal to client then indeed you can use a for loop. 如果要删除成员item等于client所有节点,则确实可以使用for循环。

For example 例如

void delete( Item client )
{
    for( link current = head, previous = NULL; current != NULL; )
    {
        if ( current->item == client )
        {
            link tmp = current;

            if ( previous != NULL ) 
            {
               previous->next = current->next;
               current = current->next;
            }
            else
            {
                head = current->next;
                current = head;
            }

            free( tmp );
        }
        else
        {
            previous = current;
            current = current->next;
        }
    }
}

There are two wrong points: 有两个错误的观点:

  • if the first element is the item need to be deleted, the previous of this item is not exist, and the code p->next = ... is not correct action. 如果第一个元素是需要删除的项目,则该项目的前一个不存在,并且代码p-> next = ...是不正确的操作。 You should change the head of the list, it is right action. 您应该更改列表的开头,这是正确的操作。
  • when you delete current item(free(r)), so if you call x=x->next your program maybe crash. 当您删除当前项(free(r))时,因此,如果调用x = x-> next,则程序可能会崩溃。 You must backup x->next before you delete. 删除之前,必须先备份x-> next。 And the for loop of you need to change 而且您的for循环需要更改

When you delete an item, you must know which pointer to update. 删除项目时,必须知道要更新的指针。 That means you must know about the previous node in the list. 这意味着您必须了解列表中的上一个节点。 Vlad's answer does this by keeping an extra previous variable, your first code does that by looking at the pointer pointed to by the current node. Vlad的答案是通过保留一个额外的previous变量来实现的,您的第一个代码通过查看当前节点所指向的指针来做到这一点。 Both have to treat deletion from the head as special case. 两者都必须将头部删除视为特殊情况。

Your second code tries to simplify the code, but you lose the special case of deletion at the head and also update the iterator link after deletion, which you shouldn't. 您的第二个代码试图简化代码,但是您丢失了删除开头的特殊情况,并且在删除后也更新了迭代器链接,这是不应该的。 (Your original code correctly places the update in an else clause.) (您的原始代码正确地将更新放置在else子句中。)

A method to get rid of the special case of deletion at the head is to introduce one level of indirection by iterationg via a pointer to node pointer. 摆脱头部特殊删除的一种方法是通过指向节点指针的指针通过迭代引入一个间接级别。 That pointer holds the address of the "previous" pointer – the list head or the next pointer of the previous node. 该指针保存“上一个”指针的地址-列表头或上next节点的next指针。 The rest is more or less like your original code, expect that the current node now is at *l instead of at l->next : 其余部分或多或少类似于您的原始代码,希望当前节点现在位于*l而不是l->next

void delete(Item client)
{
    link *l = &head;

    while (*l) {
        if ((*l)->client == client) {
            link r = *l;

            *l = (*l)->next;
            free(r);
        } else {
            l = &(*l)->next;
        }
    }
}

This code removes all items that match client ; 此代码删除所有与client匹配的项目; I reckon that is the desired behaviour. 我认为这是理想的行为。 (The additional indirection also works for insertion.) (附加的间接方式也适用于插入。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM