I can't wrap my head around how does Head also changes whenever assigning a new Node to Tail. Do I miss something important about how Class works? Please explain in detail to me.
class Node {
constructor(val){
this.val = val
this.next = null
}
}
class SinglyLinkedList {
constructor(){
this.head = null
this.tail = null
this.length = 0
}
push(val){
let newNode = new Node(val)
if(!this.head){
this.head = newNode // <-- this line
this.tail = this.head
}else{
this.tail.next = newNode
this.tail = newNode
}
this.length
return this
}
}
let list = new SinglyLinkedList()
slist.push(1)
slist.push(2)
slist.push(3)
console.log(JSON.stringify(list))
//output {"head":{"val":1,"next":{"val":2,"next":
// {"val":3,"next":null}}},"tail":{"val":3,"next":null},"length":3}
Doesn't Head only get the first Node object?
CodePudding user response:
This is the case when the list is empty and the first item is added. - if(!this.head)
CodePudding user response:
It might help to visualise this.
When let list = new SinglyLinkedList() has executed we can picture the state like this:
slist
│
▼
┌────────────┐
│ head: null │
│ tail: null │
│ length: 0 │
└────────────┘
Now let's see what happens when slist.push(1) is called. While executing that method, this will be slist. First newNode is created as new Node(val):
this
slist newNode
│ │
▼ ▼
┌────────────┐ ┌────────────┐
│ head: null │ │ val: 1 │
│ tail: null │ │ next: null │
│ length: 0 │ └────────────┘
└────────────┘
As this.head is null, !this.head is a truthy expression, so the if block gets executed. this.head = newNode results in this state:
this
slist newNode
│ │
▼ ▼
┌────────────┐ ┌────────────┐
│ head: ────────► │ val: 1 │
│ tail: null │ │ next: null │
│ length: 0 │ └────────────┘
└────────────┘
After this.tail = this.head executes, we get this:
this
slist newNode
│ │
▼ ▼
┌────────────┐ ┌────────────┐
│ head: ────────► │ val: 1 │
│ tail: ────────► │ next: null │
│ length: 0 │ └────────────┘
└────────────┘
And finally, the length property is incremented. return this is executed, but that return value is not used by the caller. So the caller sees this:
slist (returned)
│
▼
┌────────────┐ ┌────────────┐
│ head: ────────► │ val: 1 │
│ tail: ────────► │ next: null │
│ length: 1 │ └────────────┘
└────────────┘
With the next call of push, we again get a newNode:
this
slist newNode
│ │
▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ head: ────────► │ val: 1 │ │ val: 2 │
│ tail: ────────► │ next: null │ │ next: null │
│ length: 1 │ └────────────┘ └────────────┘
└────────────┘
This time head is not null and so we get into the else block. There we execute this.tail.next = newNode:
this
slist newNode
│ │
▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ head: ────────► │ val: 1 │ │ val: 2 │
│ tail: ────────► │ next: ────────► │ next: null │
│ length: 1 │ └────────────┘ └────────────┘
└────────────┘
And finally this.tail = newNode and this.length are executed:
this
slist newNode
│ │
▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ head: ────────► │ val: 1 │ │ val: 2 │
│ tail: ───────┐ │ next: ────────► │ next: null │
│ length: 2 │ │ └────────────┘ └────────────┘
└────────────┘ │ ▲
└──────────────────────┘
Repeat this process for the call of slist.push(3) and the caller ends up with:
slist
│
▼
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ head: ────────► │ val: 1 │ │ val: 2 │ │ val: 3 │
│ tail: ───────┐ │ next: ────────► │ next: ────────► │ next: null │
│ length: 2 │ │ └────────────┘ └────────────┘ └────────────┘
└────────────┘ │ ▲
└─────────────────────────────────────────┘
