Pushing on a Linked List (this.tail.next)

class Node{
  constructor(val){
    this.val = val
    this.next = null
  }

}

class SinglyLinkedList{
    constructor(){
      this.head = null
      this.tail = null
    }
  
  push(val){
   let newNode = new Node(val)
   
   if(!this.head){
       this.head = newNode
       this.tail = this.head
   } else {
      this.tail.next = newNode
      this.tail = newNode 
    }
    return this
  }
}

let test = new SinglyLinkedList();

console.log(test.push('1'));
console.log(test.push('2'));

For the code above, I’m having an extremely difficult time understanding how the

else {
      this.tail.next = newNode
      this.tail = newNode 
    }

works. When pushing values, the head gets updated without being referenced in the else statement. How does this.tail.next update the head? To me, that seems like it should update whatever is in the tail? I’m just not seeing it?

Hello!

When pushing values, the head gets updated

That’s not correct. The head should not be updated unless it’s removed. I mean, the head always points to the first element and the tail to the last. So, if we had this linked list: [1, 2, 3], the head would be 1 and the tail the 3.

If you pushed a 4, then that becomes the tail, but the head still doesn’t change (and it shouldn’t).

If the list had just one element: [1], then both --the tail and the head-- would point to the same element.

Does it make sense?

Hi @skaparate, thanks for the reply, that makes sense. But I guess my confusion is how does “next” in the head have the items pushed to it? I understand the tail gets updated each time something is added, but how does the added item end up on the “next” portion of the head?

I see!

Let’s assume we have an empty linked list.

  1. The first time we push it checks that the head exists. Since it doesn’t, then the created node it’s set as head and tail.

  2. The second time something is pushed, the current tail’s next node (remember that the current tail is the head too: this.tail = this.head) is set to the next node, which ends up being the same as: this.head.next = newNode. Also the tail gets updated to point to the newNode. In essence, this is creating a circular reference between the tail and the head.

  3. Afterwards every push just updates the previous tail.next to point to the new node (the new tail).

Maybe a graphical example of what happens may help more :stuck_out_tongue:: click here.

@skaparate, thank you so much so that explanation! I think I am 95% there! The explanation of this.tail = this.head helped out tremendously.

The last time I’m having issues with is how items get continually added after 2 items have already been added. In my mind it should be this.tail.next, then this.tail.next.next, then this.tail.next.next.next.

I need to draw it out to see it fully.

Thank you for your explanation it really really helped me out!

@skaparate, I think I got it! Thank you so much for your help. I see how the circular referencing works now. I literally had to sit down and draw it on a piece of paper. Thank you for your time!

1 Like

Awesome :slight_smile:! That’s something I’ve (everyone?) done many times: write it on paper to understand what each iteration does.