Deleting first node in linked list has problems

前端 未结 3 1593
鱼传尺愫
鱼传尺愫 2021-01-25 10:05

I\'m implementing a linked list and it needs to have a function that when given a head of a linked list and a cstring, it finds and deletes a node whose value is the cstring.

3条回答
  •  长发绾君心
    2021-01-25 11:01

    The first thing to realise is that removing an element from a linked list involves changing exactly one pointer value: the pointer that points at us. This can be the external head pointer that points to the first list element, or one of the ->next pointers inside the list. In both cases that pointer needs to be changed; its new value should become the value of the ->next pointer of the node to be deleted.

    In order to change some object (from within a function) we need a pointer to it. We need to change a pointer, so we will need a pointer to pointer.

    bool findAndRemove1(node **ptp, char *phrase)
    {
        node *del;
    
        for( ;*ptp; ptp = &(*ptp)->next) {
            if( !strcmp((*ptp)->entry, phrase) ) { break; } //found
            }
    
          /* when we get here, ptp either
          ** 1) points to the pointer that points at the node we want to delete
          ** 2) or it points to the NULL pointer at the end of the list
          **    (in the case nothing was found)
          */
        if ( !*ptp) return false; // not found
    
        del = *ptp;
        *ptp = (*ptp)->next;
        free(del);
        return true;
    }
    

    The number of if conditions can even be reduced to one by doing the dirty work in the loop,and returning from the loop but that would be a bit of a hack:

    bool findAndRemove2(node **ptp, char *phrase)
    {
    
        for( ;*ptp; ptp = &(*ptp)->next) {
            node *del;
            if( strcmp((*ptp)->entry, phrase) ) continue; // not the one we want
    
              /* when we get here, ptp MUST
              ** 1) point to the pointer that points at the node we want to delete
              */
            del = *ptp;
            *ptp = (*ptp)->next;
            free(del);
            return true;
            }
        return false; // not found
    }
    

    But what if the list is not unique, and we want to delete all the nodes that satisfy the condition? We just alter the loop logic a bit and add a counter:

    unsigned searchAndDestroy(node **ptp, char *phrase)
    {
        unsigned cnt;
    
        for( cnt=0 ;*ptp; ) {
            node *del;
            if( strcmp((*ptp)->entry, phrase) ) { // not the one we want
                 ptp = &(*ptp)->next;
                 continue; 
                 }
              /* when we get here, ptp MUST point to the pointer that points at the node we wish to delete
              */
            del = *ptp;
            *ptp = (*ptp)->next;
            free(del);
            cnt++;
            }
        return cnt; // the number of deleted nodes
    }
    

    Update: and a driver program to test it:

    #include 
    #include 
    #include 
    #include 
    
    typedef struct  list {
            struct list *next;
            char entry[20];
            } node;
    
    void node_add( node **ptp, char *str)
    {
    node *new;
    
    for (   ; *ptp; ptp = &(*ptp)->next) {
            if (strcmp ((*ptp)->entry, str) < 0) continue;
            }
    new = malloc (sizeof *new);
    strcpy(new->entry, str);
    new->next = *ptp;
    *ptp = new;
    }
    
    int main (void)
    {
    node *root = NULL;
    unsigned cnt;
    
    node_add (& root, "aaa" );
    node_add (& root, "aaa" );
    node_add (& root, "bbb" );
    node_add (& root, "ccc" );
    node_add (& root, "aaa" );
    cnt = seachAndDestroy( &root, "bbb" );
    printf("Cnt(bbb) := %u\n", cnt );
    cnt = seachAndDestroy( &root, "ccc" );
    printf("Cnt(ccc) := %u\n", cnt );
    cnt = seachAndDestroy( &root, "aaa" );
    printf("Cnt(aaa) := %u\n", cnt );
    printf("Root now = %p\n", (void*) root );
    
    return 0;
    }
    

    And the output:

    plasser@pisbak:~/usenet$ ./a.out
    Cnt(bbb) := 1
    Cnt(ccc) := 1
    Cnt(aaa) := 3
    Root now = (nil)
    

提交回复
热议问题