简体   繁体   中英

Changing nodes in linked list

This is somewhat mind-boggling

i will try to explain my doubt.

Check this function for example:

void snoc(Lint *l, int val){
    Lint i, new;

    new = (Lint) malloc(sizeof(Nodo));
    new->value = val;
    new->next = NULL;

    i=(*l);

    while(i->next!=NULL){
        i=i->next;
    }

    i->next = new;
}

I understand the concept behind and i have no trouble working with lists, taking in consideration that i can't iterate through the list using the list initial pointer itself (if i do this, i would lose the initial pointer right)

The thing is, making i=(*l) and afterwards iterating through the list using i=i->next, is making the i variable becoming in constant change.

In this particular example, the original list will not change until i find the end of the linked list, and then i make an attribution and voilá! I insert an element at the end.

My doubt is, if by changing the i , and making i->next = new at the end, wouldn't that mean that everytime i make i=i->next , change ALL the nodes in the original list?

Another example would be init:

void init (Lint *l){
    Lint i, prev;
    i=(*l);
    prev=NULL;

    while(i!=NULL){
        if( (i->next)->next==NULL){
            i->next = NULL;
        }
        i=i->next;
    }
}

if i do this, the last element will be removed, by changing the i->next to NULL, at the right moment. But before that, i've been making changes to the i itself again, by telling i=i->next

If i were to make this change to the (*l) itself (by doing (*l)=(*l)->next ) i would be ruining the original list .

I really hope you guys can understand my doubt.

Yes, we do understand your confusion, and it comes from not working out the list pointers on a piece of paper so you can visualize what is taking place. Always use a diagram when you are working node link issues. For example in your case with your singly linked-list, current node called i (dubious choice of name) and your new node called new a helpful diagram would be:

Singly Linked-List (non-circular)

         Tail                 Current                Head
      (list start)               i                   new
     +------------+        +------------+        +------------+
     |   Payload  |        |   Payload  |        |   Payload  |
     +------------+        +------------+        +------------+
     |   Next     |------->|   Next     |------->|   Next     |--->NULL   
     +------------+        +------------+        +------------+        

Now, I bet you can tell what:

changing i , and making i->next = new at the end

would do. This isn't a dig or meant to be condescending, it is really the way you need to work out linked-list issues until you have done it enough you can visualize the pointer wiring in your head. This is even more important when you get to circular or doubly-linked list insertions and deletions. No matter what the problem, if you just write it down and label all the connections that are being made or broken, you can then code it cleanly in your editor.

with some minors modifications your code is like this

void snoc(Lint *l, int val)
{
   Lint i, new;
   new = (Lint) malloc(sizeof(Nodo));
   new->value = val;
   new->next = NULL;
   i = *l;  
   if(!(*l))
   {
     *l = new;
     return;
   }
   while(i->next) i = i->next;   // (1)
   i->next = new;                // (2)
}

and, this is its explanation:

In (1) we walk throught the linked list until its end. We know we are at the end because i->next (which point after each loop step to the next nodo item) is null so in that case, we make i->next point to the newly created nodo item in (2). But l never changed during the function, l is always pointing to the begining of our linked list so the purpose of this function is to add a new element at the end without changing the value of l .

but also we can initialize our linked list with this function...for example:

   Lint l = NULL;
   snoc(&l, 10); // l will be initialized with a new nodo item with 10 as the value its value member 

(0) checks if l is null in that case we make *l point to the newly allocated nodo item and return...so initialization done.

I add another way for the code above

void snoc(Lint *l, int val)
{
   Lint now, new, previous;
   new = (Lint) malloc(sizeof(Nodo));
   new->value = val;
   new->next = NULL;
   if(!(*l)) // (0)
   {
     *l = new;
     return;
   }
   for(now = *l; now; now = now->next)previous = now;
   previous->next = new;
}

I am not sure I understand your question, but why don't you simply copy the pointer? You can keep a pointer to the initial element and use a second one to traverse though it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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