How does this.head gets directly updated when not updated? - javascript

My LinkedList Class has two properties
this.head
this.size
this.head is used to contain the list of objects. Simple logic says, if I update this.head , its value should be updated. If I, however, assign its value to some other variable and then try to update that variable, then the original this.head shouldn't update.
Eg:
printElements(){
let current = this.head;
while(current){
console.log(current.data)
current = current.next;
}
};
But this piece of code contradicts that situation. I don't know why this.head is getting updated here when it's not directly referenced.
insertAt(data, index){
if(index > 0 && index > this.size)
return
const node = new Node(data);
let current, previous;
current = this.head;
let count = 0;
while(count < index){
previous = current;
count++;
current = current.next;
}
node.next = current;
previous.next = node;
};
The entire piece of code
class Node{
constructor(data, next = null){
this.data = data;
this.next = next;
}
}
class LinkedList{
constructor(){
this.head = null;
this.size = 0;
};
insert(data){
this.head = new Node(data, this.head);
this.size++;
};
insertAt(data, index){
if(index > 0 && index > this.size)
return
const node = new Node(data);
let current, previous;
current = this.head;
let count = 0;
while(count < index){
previous = current;
count++;
current = current.next;
}
node.next = current;
previous.next = node;
};
printElements(){
let current = this.head;
while(current){
console.log(current.data)
current = current.next;
}
};
}

Let's take a stab at minimal examples that show the behaviour you're asking about, keeping it mostly language agnostic, as this is not specific to JS.
Why doesn't this snippet print 20? It prints 10 instead.
b = new Node(20);
a = new Node(10, b);
c = a;
c = c.next;
console.log(a.data);
Why doesn't this snippet print 10? It prints 20 instead.
b = new Node(10);
a = b;
a.data = 20;
console.log(b.data);
Both of these questions arise from conflating variables and objects with each other. The two concepts are related but distinct.
When we say something like b = new Node(20);, we're declaring a variable b, instantiating an object Node(20), and referencing the object from the variable. b holds a reference to Node(20). If we say b.data = 30;, now b holds a reference to Node(30). This was the same Node as before, but its data has changed. So far, the object/variable distinction hasn't revealed itself.
We could also say a = b;, as in the second example. This means we have two variables both referencing the same Node(20) object. If we say a.data = 30;, then the object referenced by variable a's data is set to 30. So since there's only one Node object, b.data and a.data are both 30.
When we say something like c = a; c = c.next;, the Node referenced by a is still there, still referenced by a. a is like an arrow, pointing at Node(10). c is another arrow, also pointing at Node(10). c = c.next; has no impact on a. It's just changing what c is pointing to.

Related

Implement the addInPos method inside the LinkedList prototype in Javascript

I need to implement the addInPos method inside the LinkedList prototype but I don't know what it is bad in my code...because the test no pass.
Implement the addInPos method inside the LinkedList prototype that must add an element in the indicated position. Both data will be provided as a parameter (pos, value). Where "pos" will be the position in which the "value" value should be added. In the event that the position in which the insertion is to be made is invalid, that is, it exceeds the size of the current list, it must return false.
If the node was added correctly return true.
Note: the zero position corresponds to the head of the LinkedList.
My code:
LinkedList.prototype.addInPos = function(pos, value) {
if(pos > this.size) {
return false;
}
const newNode = new Node(pos, value);
let current = this.head;
let previous;
if(pos === 0) {
newNode.next = current;
current.prev = newNode;
this.head = newNode;
} else {
for(let i = 0; i < pos; i++){
previous = current;
current = current.next;
}
newNode.next = current;
newNode.prev = previous;
current.prev = newNode;
previous.next = newNode;
}
}
Thanks.
With your structure ideally insertAt function would look like:
var insertAt = function(head, item, index) {
var curr = head;
var count = 0;
while (curr !== null) {
if (count === index) {
var newNode = { data: item, next: curr.next, prev: curr };
curr.next = newNode;
break;
}
count++;
curr = curr.next;
}
};
insertAt(head, 2, 3);
Let me know if this works.
Also look at this LinkedList class I have created, insertAt function is currently missing, but from this stack question, I am planning to add it in my class as well.
Class GitHub
NPM package - #dsinjs/linked-list
Complete documentation

Copy List with Random Pointer - Copy not point to -

I'm trying to solve the problem below:
A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.
Return a deep copy of the list.
The Linked List is represented in the input/output as a list of n nodes. Each node is represented as a pair of [val, random_index] where:
val: an integer representing Node.val
random_index: the index of the node (range from 0 to n-1) where random pointer points to, or null if it does not point to any node.
Input: head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
Output: [[7,null],[13,0],[11,4],[10,2],[1,0]]
My idea was loop the head and create a new node with the same value and set it to my ans Node. It will be a copy because I'm creating a new one. Then, I loop again for the random pointer which looks in my ans Node the node with the value that I should point to. It works perfectly for the input above. However, if I have an input with duplicate values, the findeNode method might return an invalid Node. For example it fails for the input below:
[[3,null],[5,17],[4,null],[-9,6],[-10,3],[5,15],[0,11],[6,null],[-6,16],[3,16],[-6,11],[9,12],[-2,1],[-3,11],[-1,10],[2,11],[-3,null],[-9,7],[-2,4],[-8,null],[5,null]]
My output:
[[3,null],[5,3],[4,null],[-9,null],[-10,3],[5,15],[0,11],[6,null],[-6,13],[3,13],[-6,11],[9,12],[-2,1],[-3,11],[-1,8],[2,11],[-3,null],[-9,7],[-2,4],[-8,null],[5,null]]
Correct output:
[[3,null],[5,17],[4,null],[-9,6],[-10,3],[5,15],[0,11],[6,null],[-6,16],[3,16],[-6,11],[9,12],[-2,1],[-3,11],[-1,10],[2,11],[-3,null],[-9,7],[-2,4],[-8,null],[5,null]]
Node definition:
function Node(val, next, random) {
this.val = val;
this.next = next;
this.random = random;
};
My code:
var copyRandomList = function(head) {
if(!head) return head;
let ans = new Node(0);
let temp = ans;
let cur = head;
while(cur) {
const node = new Node(cur.val);
temp.next = node;
cur = cur.next;
temp = temp.next;
}
cur = head;
temp = ans.next;
while(cur) {
const randomNode = cur.random;
if(!randomNode) {
temp.random = null;
} else {
const node = findNode(ans, randomNode.val);
temp.random = node;
}
cur = cur.next;
temp = temp.next;
}
return ans.next;
};
const findNode = (list, val) => {
if(!val)
return null;
while(list) {
if(list.val === val)
return list;
list = list.next;
}
return null;
}

Why this JS destructuring assignment method works for reverse the singly linked list?

I am doing a leetcode question reverse singly linked list.
I tried the following code, and see if I miss the code at place 1, it will get error on result. I understand it is because it lose the reference to current.next. (Thanks for this stackoverflow post.)
function ListNode(val) {
this.val = val;
this.next = null;
}
/**
* #param {ListNode} head
* #return {ListNode}
*/
var reverseList = function(head) {
let current = head;
let prev = null;
while (current) {
current.next = prev;
prev = current;
current = current.next;
//The right one
// let save = current.next; //1
// current.next = prev;
// prev = current;
// current = save;
}
return prev
};
The problem is, I found another code showing below also works by using array destructuring assignment (the name right maybe?), but I can't understand why this work without using another variable to save the reference to the current.next.
var reverseList = function(head) {
let current = head;
let prev = null;
while (current) {
[current.next, prev, current] = [prev, current, current.next];//2
}
return prev
};
So how is the code at place 2 actually working without using another variable to save the reference to the current.next?
[current.next, prev, current] = [prev, current, current.next]; is an array destructuring syntax and it works without keeping a tempvariable explicitly because the reference is kept in an array
you can think of the above code as
const arr = [];
arr[0] = prev;
arr[1] = current;
arr[2] = current.next;
current.next = arr[0];
prev = arr[1];
current = arr[2]
where the reference of the original elements is kept within an array instead of individual variables
Using destructuring assignment for swapping variables there is no need for temporary variables.
var a = 1;
var b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
See Swapping variablesSection with Destructuring on MDN
See ECMAScript docs linked in briosheje's answer for language specs details.

Doubly Linked List in javascript

I was building linked list in javascript.
I dont understand one part.
function Node(element) {
this.element = element;
this.next = null;
this.previous = null;
}
function LList() {
this.head = new Node("head");
this.find = find;
this.findLast = findLast;
this.remove = remove;
this.insert = insert;
this.display = display;
this.dispReverse = dispReverse;
}
function find(item) {
var currNode = this.head;
while(currNode.element != item) {
currNode = currNode.next;
}
return currNode;
}
function display(list) {
var currNode = this.head.next;
while (currNode != null) {
console.log(currNode.element);
currNode = currNode.next;
}
}
function insert(newElement, item) {
var newNode = new Node(newElement);
var current = this.find(item);
newNode.next = current.next;
newNode.previous = current;
current.next = newNode;
// Why I dont need this part?
// Since new node got inserted, on my thoughts,
// the next node of the current node should point the new node as a previous one
// current.next.previous = newNode;
}
function remove(item) {
var currNode = this.find(item);
if (currNode.next != null) {
currNode.previous.next = currNode.next;
currNode.next.previous = currNode.previous;
currNode.next = null;
currNode.previous = null;
}
}
function findLast() {
var currNode = this.head;
while (currNode.next != null) {
currNode = currNode.next;
}
return currNode;
}
function dispReverse() {
var currNode = this.head;
currNode = this.findLast();
while(currNode.previous != null) {
console.log(currNode.element);
currNode = currNode.previous;
}
}
var cities = new LList();
cities.insert("Conway", "head");
cities.insert("Russellville", "Conway");
cities.insert("Carlisle", "Russellville");
cities.insert("Alma", "Carlisle");
cities.display();
cities.remove("Carlisle");
cities.display();
cities.dispReverse();
/*
Output should look like this:
Conway
Russellville
Carlisle
Alma
Conway
Russellville
Alma
Alma
Russellville
Conway
*/
Problem is the insert function!
Let's say if I have A B C node already.
And I want to insert K after B.
Currently, the next and previous of B are C and A for each.
The previous element of C is B.
Once I put K after B,
A B K C
(1) the next element of K will be C
(2) the previous element of K will be B.
(3) The next element of B is K
(4) previous element of C is K.
On the code I wrote in Insert function, each line of the codes below should process the upper statements.
(1) newNode.next = current.next;
(2) newNode.previous = current;
(3) current.next = newNode;
(4) current.next.previous = newNode;
But when I run this whole code including (4), error has occurred.
I don understand why...
Without the (4) line of codes, it works.
Is there anyone who can help me understand this?
You need to do step 4 before step 3:
current.next.previous = newNode
current.next = newNode
As it is, the reference of current.next (C) is being set to newNode (K) before you lookup the "old" current.next's previous property ( current.next.previous when points to B). Your reference to the current node is changed as soon as you assign it a new value. This is why current.next.previous is actually returning newNode.previous instead of the node reference you expect.
Your insert logic seems wrong in the last line :
current.next = newNode;
current.next.previous = newNode;
This actually means
newNode.previous=newNode;
Since you are setting the value of current.next to newNode in the 3rd statement
It should be :
newNode.next.previous = newNode.

variable always NaN

I'm learning my way into JS (but not new to programming). So, I'm trying to implement a LinkedList just to play around with JS.
It works okay except that count always returning NaN. I've googled, and thought that the reason was I wasn't initially setting the count to a number, but I did.
Below is my code:
function LinkedList() {
var head = null,
tail = null,
count = 0;
var insert = function add(data)
{
// Create the new node
var node = {
data: data,
next: null
};
// Check if list is empty
if(this.head == null)
{
this.head = node;
this.tail = node;
node.next = null;
}
// If node is not empty
else
{
var current = this.tail;
current.next = node;
this.tail = node;
node.next = null;
}
this.count++;
};
return {
Add: insert,
};
}
var list = new LinkedList();
list.Add("A");
list.Add("B");
The this in this.count refers to to the instance of the LinkedList object.
The part:
var head = null,
tail = null,
count = 0;
These are private variables and not considered a property of the LinkedList object.
What you want to do instead is:
this.head = null;
this.tail = null;
this.count = 0;
And that will make head, tail, count a property of the LinkedList object so that you can do this.count++.
Edit: To keep head, tail, count as private to the LinkedList object, your other code would be something like this:
// Check if list is empty
if(head == null)
{
head = node;
tail = node;
node.next = null;
}
// If node is not empty
else
{
var current = tail;
current.next = node;
tail = node;
node.next = null;
}
count++;
Also keep in mind that objects are pass-by-reference. So that applies to:
var current = tail;
current.next = node;
tail = node;
node.next = null;
More: If you want count to be a public property, then instead of returning:
return {
Add: insert,
};
You need to do this:
this.Add = insert;
return this;
So that the current object context gets returned upon object creation.

Categories

Resources