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 │ │ └────────────┘ └────────────┘ └────────────┘
└────────────┘ │ ▲
└─────────────────────────────────────────┘