Thread: delete function

  1. #31
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Delete 4

    Code:
      Head
      |
      v
    +---+    +---+    +---+    +---+    +---+    
    | 5 |--->| 4 |--->| 3 |--->| 2 |--->| 1 |--->NULL
    +---+    +---+    +---+    +---+    +---+
    Step 1, advance current to the correct node.
    Code:
      Head     current
      |        |
      v        v
    +---+    +---+    +---+    +---+    +---+    
    | 5 |--->| 4 |--->| 3 |--->| 2 |--->| 1 |--->NULL
    +---+    +---+    +---+    +---+    +---+

    Step 2, bypass the node to be deleted.
    Somehow, you need to make the node containing 5 point to the node containing 3.
    Code:
      Head     current
      |        |
      v        v
    +---+    +---+    +---+    +---+    +---+    
    | 5 |-+  | 4 | +->| 3 |--->| 2 |--->| 1 |--->NULL
    +---+ |  +---+ |  +---+    +---+    +---+    
          +--------+
    This is normally achieved by having another pointer variable that tracks the previous node.

    Code:
    void delete( struct node **head, int value)
    {
        struct node *current = *head;
        struct node *prev = NULL;
         
        while (current != NULL)
        {
            // Your code
    
            // the current node becomes the previous node
            prev = current;
            current = current->next;  
        }
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  2. #32
    Registered User
    Join Date
    Oct 2022
    Posts
    89
    Quote Originally Posted by Salem View Post
    Delete 4

    Code:
      Head
      |
      v
    +---+    +---+    +---+    +---+    +---+    
    | 5 |--->| 4 |--->| 3 |--->| 2 |--->| 1 |--->NULL
    +---+    +---+    +---+    +---+    +---+
    Step 1, advance current to the correct node.
    Code:
      Head     current
      |        |
      v        v
    +---+    +---+    +---+    +---+    +---+    
    | 5 |--->| 4 |--->| 3 |--->| 2 |--->| 1 |--->NULL
    +---+    +---+    +---+    +---+    +---+

    Step 2, bypass the node to be deleted.
    Somehow, you need to make the node containing 5 point to the node containing 3.
    Code:
      Head     current
      |        |
      v        v
    +---+    +---+    +---+    +---+    +---+    
    | 5 |-+  | 4 | +->| 3 |--->| 2 |--->| 1 |--->NULL
    +---+ |  +---+ |  +---+    +---+    +---+    
          +--------+
    This is normally achieved by having another pointer variable that tracks the previous node.
    This is the same process that I have done in a post #26.

    Basic process is understandable but very difficult to convert into code

  3. #33
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    Quote Originally Posted by Kittu20 View Post
    This is the same process that I have done in a post #26.
    But not what you are doing in code...

    May I suggest there's a better way to implement single linked lists with 2 sentinel nodes?
    I believe I already told this...

  4. #34
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    Sedgewick like single linked list:
    Code:
    EMPTY LIST
    
                  +------+
                  V      |
     +---+       +---+   |
     |   |------>|   |---+
     +---+       +---+
     head        tail
    This structure must obey some ground rules:

    1 - Never try to delete head or tail nodes;
    2 - Never try to add a node after tail node;
    3 - Insert or delete nodes AFTER a specific node.

    The node structure is this:
    Code:
    struct node { struct node *next; };
    Without any data! Only the link to the next node. The list structure is like this:
    Code:
    struct list { struct node head, tail; };
    Yep... head and tail aren't pointers! And we must initialize an object of this structure with this macro:
    Code:
    #define INIT_LIST(list__) (struct list){ .head.next = &(list_).tail, \
                                             .tail.next = &(list__).tail }
    Like this:
    Code:
    struct list mylist = INIT_LIST(mylist);
    These structures allow polymorphic nodes. All you have to do is to make sure the first member of any node is the next pointer. Like in:
    Code:
    struct mynode {
      struct node *next;
    
      // ... a bunch of my node objects here
    };
    Here's the insert after node function:
    Code:
    void slist_insertAfter( struct node *node, struct node *new )
    {
      new->next = node->next;
      node->next = new;
    }
    And the delete after:
    Code:
    // return NULL if next node is tail.
    struct node *slist_deleteAfter( struct node *node )
    {
      struct node *next;
    
      next = node->next;
      if ( next == next->next )
        return NULL;
    
      node->next = next->next;
    
      return next;
    }
    In this particular example I choose to return NULL if the next node is tail.
    To test if a list is empty is very simple:
    Code:
    _Bool slist_empty( struct list *list )
    { return list->head.next == &list->tail; }
    Another useful routine could be:
    Code:
    _Bool slist_istail( struct node *node )
    { return node == node->next; }
    To empty the entire list is simple:
    Code:
    void slist_clear( struct list *list, void (*dtor)( void * ) )
    {
      while ( 1 )
      {
        struct node *node;
    
        node = slist_deleteAfter( &list->head );
        if ( ! node )
          break;
    
        if ( dtor )
          dtor( node );
      }
    }
    Where's the nodes allocations? You may ask. They are NOT part of the list manipulation (and never should be). Here's an example of usage:
    Code:
    // macro for list iteration.
    #define for_each(iter__,list__) \
      for ( (iter__) = (list__)->head.next; \
            (iter__) != (iter__)->next; \
            (iter__) = (iter__)->next )
    
    int main( void )
    {
      struct list list = LIST_INIT(list);
      struct node *i; // list iterator.
    
      struct mynode {
        struct node *next;
    
        int value;
      };
    
      struct mynode *p;
    
      // As an example I did not test the success or failure of malloc here!
      // you should do it... Notice the allocation is NOT part of the
      // list manipulation routines.
    
      p = malloc( sizeof *p ); p->value = 1;
      slist_insertAfter( &list.head, (struct node *)p ); i = (struct node *)p;
    
      p = malloc( sizeof *p ); p->value = 2;
      slist_insertAfter( i, (struct node *)p ); i = (struct node *)p;
    
      p = malloc( sizeof *p ); p->value = 3;
      slist_insertAfter( i, (struct node *)p );
    
      for_each( i, &list )
      {
        p = (struct mynode *)i;
    
        printf( "%d ", p->value );
      }
      
      putchar( '\n' );
    
      slist_clear( &list, free );   // using free() as destructor.
    }
    Last edited by flp1969; 01-28-2023 at 02:27 PM.

  5. #35
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    Here's how simple the slist_empty, slist_insertAfter and slist_deleteAfter is compiled to assembly for x86-64:
    Code:
    slist_empty:
        lea      rax, [rdi+8]
        cmp      rax, [rdi]
        sete     al
        ret
    
    slist_insertAfter:
        mov      rax, [rdi]
        mov      [rsi], rax
        mov      [rdi], rsi
        ret
    
    slist_deleteAfter:
        mov      rax, [rdi]
        mov      rdx, [rax]
        cmp      rdx, rax
        je       .is_tail
        mov      [rdi], rdx
        ret
    
        align 4
    .is_tail:
        xor      eax, eax
        ret
    Just make them static inline and they will be extremely fast.

    Compare this to the usual last node points to NULL approach and you'll see we have much less "special cases".
    Last edited by flp1969; 01-28-2023 at 02:20 PM.

  6. #36
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    Another thing: If you plan to unlink the next node based on some criteria, the for_each macro is no good. We must keep track of the next node, after it. So, this other macro is safer, in that cases:
    Code:
    #define for_each_safe(iter__,tmp__,list__) \
      for ( (iter__) = (list__)->head.next, (tmp__) = (iter__)->next; \
            (iter__) != (iter__)->next; \
            (iter__) = (tmp__) )
    The usage:
    Code:
    struct node *i; // iterator
    struct node *tmp; // temporary (used only inside for_each_safe)
    
    for_each_safe( i, tmp, &list )
    {
      struct mynode *p = (struct mynode *)i;
    
      // some criteria...
      if ( p->value == 2 ) slist_deleteAfter( i, free );
    }

  7. #37
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    @flp1969 The assembler isn't helpful at all.


    > This is the same process that I have done in a post #26.
    You've only drawn the end result.
    You need to draw all the steps taken if you hope to understand what the code needs to do.

    Deleting node 2
    Code:
    p = NULL
    c = Head
    
      c
    +---+    +---+    +---+    +---+    +---+    
    | 5 |--->| 4 |--->| 3 |--->| 2 |--->| 1 |--->NULL
    +---+    +---+    +---+    +---+    +---+    
    Is c pointing at 2? No - advance
    p = c ; c = c->next;
    
      p        c                             
    +---+    +---+    +---+    +---+    +---+    
    | 5 |--->| 4 |--->| 3 |--->| 2 |--->| 1 |--->NULL
    +---+    +---+    +---+    +---+    +---+    
    Is c pointing at 2? No - advance
    p = c ; c = c->next;
    
               p        c                    
    +---+    +---+    +---+    +---+    +---+    
    | 5 |--->| 4 |--->| 3 |--->| 2 |--->| 1 |--->NULL
    +---+    +---+    +---+    +---+    +---+    
    Is c pointing at 2? No - advance
    p = c ; c = c->next;
    
                        p        c           
    +---+    +---+    +---+    +---+    +---+    
    | 5 |--->| 4 |--->| 3 |--->| 2 |--->| 1 |--->NULL
    +---+    +---+    +---+    +---+    +---+    
    Is c pointing at 2? Yes!
    So now you're in the situation where the current pointer is pointing to the node to delete, and the previous pointer is pointing to its predecessor.


    Cartoon Guide to Data Structures — Singly Linked Lists | by Rajesh Pillai | Full Stack Engineering | Medium


    > Basic process is understandable but very difficult to convert into code
    Then you haven't understood it.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #38
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    Quote Originally Posted by Salem View Post
    @flp1969 The assembler isn't helpful at all.
    It is there just to show what the C compiler creates and to show the three routines are compiled to a very simple form.
    Ignore it if you don't like.

    It's not 'helpful'... it is 'informative'.

  9. #39
    Registered User rstanley's Avatar
    Join Date
    Jun 2014
    Location
    New York, NY
    Posts
    1,110
    Quote Originally Posted by flp1969 View Post
    It is there just to show what the C compiler creates and to show the three routines are compiled to a very simple form.
    Ignore it if you don't like.

    It's not 'helpful'... it is 'informative'.
    Not for beginner programmers that make up the majority of posters here that are learning C, and have had no exposure to Assembler code. It might as well be a foreign spoken language they can't speak or read.

    Stick to giving answers and sample code in C, in this, the C forum.

  10. #40
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    Quote Originally Posted by rstanley View Post
    Not for beginner programmers that make up the majority of posters here that are learning C, and have had no exposure to Assembler code. It might as well be a foreign spoken language they can't speak or read.

    Stick to giving answers and sample code in C, in this, the C forum.
    I don't care about "the majority" and won't restrict my answers, posts or opinions...
    Unless is writen, somewhere, that this forum is ONLY for beginners. If it is the case I'll ask to DELETE my account AND my posts.

  11. #41
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    It's not "helpful" because it's about as useful as dumping calculus on someone who's barely got to grips with addition and subtraction.

    It's not "helpful" to dump a complete re-design of a linked list on the OP because you believe it's "better". You've no idea what the terms of reference are for the OP, so it's no good them copy/pasting something way outside their experience.

    > I don't care about "the majority" and won't restrict my answers, posts or opinions...
    Sure, just don't expect people to keep quiet about it either.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  12. #42
    Registered User
    Join Date
    Oct 2022
    Posts
    89
    don't know what to do after this

    Code:
     #include<stdio.h>#include<stdlib.h>
     
    struct node
    {
        int data;
        struct node *next;
    };
     
    void delete( struct node **head, int value)
    {
    	struct node *current = *head;
    	struct node *prev = NULL;
    	
        while (current != NULL)
    	{
    	  if ( current-> data == 2)
    	  {
    		  printf("found = %d \n", value);
    	  }		
           	  
    	  prev = current;
    	  current = current -> next;
    	  
    	}
    }
    
    
    void instert( struct node **current, int value)
    {
        struct node *new = malloc(sizeof(struct node));
         
        if ( new != NULL)
        {
            new-> data = value;
            new -> next = *current;
            *current = new;
        }
    }
     
    void List(struct node *current)
    {
        while (current !=NULL)
        {
            printf("%d -> ", current -> data);
            current = current -> next;
        }
        printf("NULL\n");
    }
     
     
    int main ()
    {
        struct node *head = NULL;   
         
        instert(&head, 1); 
        instert(&head, 2);
        instert(&head, 3);
        instert(&head, 4);
        instert(&head, 5);
        List(head);
        delete (&head,4);
        List(head);
        delete (&head,3);
        List(head);
        delete (&head,5);
     //   List(head);
        printf("\n");
        return 0;
    }

  13. #43
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > if ( current-> data == 2)
    Try comparing with the value parameter.

    Well you look at your diagrams, and that you have two pointers called prev and current.

    Then you stare at this diagram.
    Code:
    prev     current
      |        |
      v        v
    +---+    +---+    +---+    +---+    +---+    
    | 5 |-+  | 4 | +->| 3 |--->| 2 |--->| 1 |--->NULL
    +---+ |  +---+ |  +---+    +---+    +---+    
          +--------+
    Then you consider the possibility of what
    prev->next = current->next;
    might do.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. List - Why my delete function doesn't delete?
    By juanjuanjuan in forum C Programming
    Replies: 7
    Last Post: 12-09-2014, 10:10 PM
  2. BST delete function
    By spikestar in forum C++ Programming
    Replies: 0
    Last Post: 08-31-2010, 08:55 PM
  3. Delete Function for AVL Trees
    By Lost in forum C Programming
    Replies: 5
    Last Post: 08-24-2009, 10:34 AM
  4. a simple delete function
    By manav in forum C++ Programming
    Replies: 20
    Last Post: 12-31-2007, 07:17 PM
  5. does C have a delete function??
    By aspand in forum C Programming
    Replies: 12
    Last Post: 05-17-2002, 03:14 PM

Tags for this Thread