Switching Nodes in a double linked list causes infinite recursion - javascript

I have the following Node constructor:
const Node = function(data){
this.data = data
this.next = null
this.previous = null
}
that is used inside of my LinkedList constructor:
const LinkedList = function(){
this.head = new Node('head')
}
and I can insert nodes with the following method:
LinkedList.prototype.insert = function(item,after){
const newNode = new Node(item)
const curr = after ? this.find(after) : this.head
newNode.next = curr.next
newNode.previous = curr
curr.next = newNode
}
with the find method being:
LinkedList.prototype.find = function(item){
let currentNode = this.head
while(currentNode && currentNode.data !== item){
currentNode = currentNode.next
}
return currentNode
}
And can view the items as an array with the following method:
LinkedList.prototype.toArray = function(){
const arr = []
let currItem = this.head.next
while(currItem){
arr.push(currItem.data)
currItem = currItem.next
}
return arr
}
My issue is now I am trying to implement a switch function on the LinkedList where I can pass in two values and switch their location in the list. Below is what I have and it seems to work for items that are not next to each other:
LinkedList.prototype.switch = function(a,b){
const aNode = this.find(a),
bNode = this.find(b)
if(!aNode || !bNode){
throw new Error('Both nodes were not inside of the list')
}
const aNext = aNode.next,
aPrevious = aNode.previous,
bNext = bNode.next,
bPrevious = bNode.previous
aNode.next = bNext
aNode.previous = bPrevious
aNode.previous.next = aNode
bNode.next = aNext
bNode.previous = aPrevious
bNode.previous.next = bNode
}
I am wondering what I am doing wrong here that is causing this to make my computer hit infinite recursion when I swap elements that are right next to each other. For instance, the below lines of code works:
const list = new LinkedList()
list.insert(1)
list.insert(2,1)
list.insert(3,2)
list.switch(1,3)
list.toArray() // [3,2,1]
However if I have the following code, it
const list = new LinkedList()
list.insert(1)
list.insert(2,1)
list.switch(1,2)
list.toArray() // crashes terminal
I know it is a stupid logical error in my switch method but I cannot for the life of me figure out what.

The problem that I see is in your insert function. If you have a linked list with two items and you call insert('New Node', null) your list looks like this:
You still need to set the previous pointer to the new node like this:
LinkedList.prototype.insert = function(item,after){
const newNode = new Node(item);
const curr = after ? this.find(after) : this.head;
newNode.next = curr.next;
curr.next.previous = newNode; <----- This is the extra line
newNode.previous = curr;
curr.next = newNode;
}

If bNode.previous is null, and if you assign as the following,
aNode.previous = bPrevious
aNode.previous.next = aNode
then you are trying to reach the next field of null, which causes to crash.

Related

insert() function doesn't add nodes to the binary search tree

I'm trying to make a binary search tree. If I start with an array my function makes a binary search tree out of that array (everything fine here). like for an array like let a = [2,4,5,3,9,7,3,8,5]; the tree looks like the picture. my problem is with the insert() function. If I start with an empty array and add a node to it, it works. However, when I add a second node, that second node won't be added to my tree, and my tree is shown as having only 1 node in it (the root node). Here the snippet:
const Node = (data, left = null, right = null) => {
return {data, left, right};
};
const Tree = array => {
const remDupsAndSort = array => {
const mergeSort = array => {
if(array.length <= 1) return array;
let leftArr = array.slice(0, array.length / 2);
let rightArr = array.slice(array.length / 2);
return merge(mergeSort(rightArr), mergeSort(leftArr))
};
const merge = (leftArr, rightArr) => {
let sorted = [];
while(leftArr.length && rightArr.length){
if(leftArr[0] < rightArr[0]){
sorted.push(leftArr.shift());
}else{
sorted.push(rightArr.shift());
}
};
return [...sorted, ...leftArr, ...rightArr]
};
return mergeSort([... new Set(array)])
};
array = remDupsAndSort(array);
const buildTree = (array, start, end) => {
if(start > end) return null;
let mid = Math.floor((start + end) / 2);
let node = Node(array[mid]);
node.left = buildTree(array, start, mid - 1);
node.right = buildTree(array, mid + 1, end);
return node;
};
const insert = value => {
if(!root) return root = Node(value);
current = root;
while(current){
if(value < current){
current = current.left
}else{
current = current.right
}
}
current = Node(value)
// if(!current){
// current = Node(value)
// // }else{
// if(value < current){
// current.left = insert(value, current.left)
// }else{
// current.right = insert(value, current.right)
// }
// }
return root
};
const prettyPrint = (node = root, prefix = '', isLeft = true) => {
if(node){
if (node.right !== null) {
prettyPrint(node.right, `${prefix}${isLeft ? '│ ' : ' '}`, false);
}
console.log(`${prefix}${isLeft ? '└── ' : '┌── '}${node.data}`);
if (node.left !== null) {
prettyPrint(node.left, `${prefix}${isLeft ? ' ' : '│ '}`, true);
}
}else{
console.log(node)
}
}
let root = buildTree(array, 0, array.length - 1);
return {root, prettyPrint, insert}
};
let a = [2,4,5,3,9,7,3,8,5];
let b = [];
let c = [1,2,4,5,6,7]
let f = Tree(a)
let d = Tree(b)
let e = Tree(c)
d.insert(4)
// d.insert(8) ---> doesn't work
// d.prettyPrint()
// f.insert(1) ---> doesn't work
f.prettyPrint()
// e.prettyPrint()
// console.log(d.root)
if I run d.prettyPrint() I'll get └── 4 just as expected. But if I run d.insert(8) after that 8 isn't added to the tree and the code returns └── 4 again. To make matters more confusing if I console.log(d.root) it returns null even though my prettyPrint function returns └── 4 as the root.
Clearly I expect the nodes be added to the tree. On one of my attempts I tried to write the code like this:
const insert = (value, current = root) => {
if(!current){
current = Node(value)
}else{
if(value < current){
current.left = insert(value, current.left)
}else{
current.right = insert(value, current.right)
}
}
return current
};
even though I assigned current = root the code returned null for d.insert(4)
There are these issues in your insert function:
current is implicitly defined as a global variable -- this wouldn't parse in strict mode. It should be declared as a local variable, using let
The value is compared with a node object instead of with the data of that node. So value < current should be changed to value < current.data
The assignment of the new node object to current -- after the loop -- will not mutate the tree. It merely assigns that object to that variable. Such assignment can never change the tree, just like current = current.right does not mutate the tree either. You need instead to assign the new node to either the left or right property of the parent of current. So this assignment should happen one step earlier.
Correction:
const insert = value => {
if(!root) return root = Node(value);
let current = root; // Define with `let`
while(current){
if(value < current.data){ // Compare with the data, not the node
// Mutate the parent node when inserting
if (!current.left) return current.left = Node(value);
current = current.left
}else{
if (!current.right) return current.right = Node(value);
current = current.right
}
}
};

I am looking at an iterative solution of checking whether a tree is symmetric

I have the following code:
class TreeNode {
constructor(val) {
this.val = val
this.left = this.right = null
}
}
const isSymmetric = root => {
if (!root) return true
let stackP = []
let stackQ = []
let currentP = root
let currentQ = root
while ((currentP && currentQ) || (stackP.length && stackQ.length)) {
while (currentP) {
stackP.push(currentP)
currentP = currentP.left
}
while (currentQ) {
stackQ.push(currentQ)
currentQ = currentQ.right
}
console.log(stackP, stackQ, 'after push')
currentP = stackP.pop()
currentQ = stackQ.pop()
console.log(stackP, stackQ, 'after 1 iterative pop')
if ((currentP.val !== currentQ.val) || (stackP.length !== stackQ.length)) return false
console.log(currentP, currentQ, 'after if statement')
// confused as to why we are setting it to the opposite here
currentP = currentP.right
currentQ = currentQ.left
console.log(currentP, currentQ, 'after opp DECLARATION')
}
return true
}
//example 1
const tree1 = new TreeNode(1)
tree1.left = new TreeNode(2)
tree1.right = new TreeNode(2)
tree1.left.left = new TreeNode(3)
tree1.left.right = new TreeNode(4)
tree1.right.left = new TreeNode(4)
tree1.right.right = new TreeNode(3)
//example 2
const tree2 = new TreeNode(1)
tree2.left = new TreeNode(2)
tree2.right = new TreeNode(2)
tree2.left.right = new TreeNode(3)
tree2.right.right = new TreeNode(3)
console.log(isSymmetric(tree1));
console.log(isSymmetric(tree2));
However, I am confused with the following two lines:
currentP = currentP.right
currentQ = currentQ.left
I am not sure why this is done. I tried following along with console logging, but am not able to follow. I would expect currentP to maintain itself following the original pattern which is set to the left, but it seems after popping the P and Q they are now traversing to the right. I don't understand why. Can anyone clarify?
let's say we have the following tree
A
/ \
B B
/ \ / \
C D D C
tracking currentP and currentQ should give the following values A, B, C, C, null, B, D, null, A. But when we get to A flowing through the logic it seems we are in an infinite loop. Unless I am not tracking it correctly. After we declare currentP and currentQ to be 'A' we should enter the while loops again, essentially pushing B and C back again, am I missing something?
Given this tree:
A
/ \
B C
/ \ / \
D E F G
First it walks all the way to the left (stackP = B, D) stacking them, and to the right (stackQ = C, G). Then compare the last leafs (D, G). Then take their siblings (E, F) and compare - That's the part you were talking about. Then pop their parents (B, C) and compare.
Here's the program with some debug info that will give you a better idea of what it is doing:
class TreeNode {
constructor(val) {
this.val = val;
this.left = this.right = null;
}
}
function serialize(arr) {
return arr.map(e => e.val).join(",");
}
const isSymmetric = (root) => {
if (!root) return true;
let stackP = [];
let stackQ = [];
let currentP = root;
let currentQ = root;
while ((currentP && currentQ) || (stackP.length && stackQ.length)) {
while (currentP) {
stackP.push(currentP);
console.log(`Pushing ${currentP.val} to sP=[${serialize(stackP)}]`)
currentP = currentP.left;
}
while (currentQ) {
stackQ.push(currentQ);
console.log(`Pushing ${currentQ.val} to sQ=[${serialize(stackQ)}]`)
currentQ = currentQ.right;
}
currentP = stackP.pop();
currentQ = stackQ.pop();
console.log(`Comparing cP=${currentP.val} cQ=${currentQ.val} sP=[${serialize(stackP)}] sQ=[${serialize(stackQ)}]`);
if (currentP.val !== currentQ.val || stackP.length !== stackQ.length)
return false;
// confused as to why we are setting it to the opposite here
currentP = currentP.right;
currentQ = currentQ.left;
console.log(`Looping cP=${currentP ? currentP.val : "null"} cQ=${currentQ ? currentQ.val : "null"} sP=[${serialize(stackP)}] sQ=[${serialize(stackQ)}]`);
}
return true;
};
//example 1
const tree1 = new TreeNode(1)
tree1.left = new TreeNode(2)
tree1.right = new TreeNode(2)
tree1.left.left = new TreeNode(3)
tree1.left.right = new TreeNode(4)
tree1.right.left = new TreeNode(4)
tree1.right.right = new TreeNode(3)
//example 2
const tree2 = new TreeNode(1)
tree2.left = new TreeNode(2)
tree2.right = new TreeNode(2)
tree2.left.right = new TreeNode(3)
tree2.right.right = new TreeNode(3)
console.log(isSymmetric(tree1));
console.log(isSymmetric(tree2));

Check If Linked List is Palindrome in JavaScript

I have written the following function in JavaScript to check if a singly Linked List is a palindrome. However, I'm failing 2 out of 10 tests, and I can't figure out why.
Here are the tests I'm falling.
l: [0, 1, 0]
l: [1, 1000000000, -1000000000, -1000000000, 1000000000, 1]
Both should return true for the palindrome, but my function is returning false.
Here's my code:
function isListPalindrome(l) {
let curr = l;
let arr = [];
if (l == null)
return true;
// push all elements of l into the stack.
// a stack in JS is an array.
while(curr != null){
arr.push(l.value);
// move ahead:
curr = curr.next;
}
let curr2 = l;
// Traverse the list again & check by popping from the stack:
while(curr2 != null){
// get the top most element on the stack:
let num = arr.shift();
// check if the node data isn't the same as the element popped:
if (curr2.value != num){
return false;
}
// move ahead:
curr2 = curr2.next;
}
return true;
}
Thank you!
Inside the first while loop you're pushing l.value but l is not being incremented so it's pushing the same value to arr.
You now have arr which is suppose to be l in reverse. In the second while loop, instead of using arr.shift() use arr.pop(). This will take the first element off the arr stack. Remember that a stack is first in, last out.
Notice also that when you're comparing the list front to back you'll reach a point of irrelevancy, the half way point. Once you know that half the values in the forward list are the same as the values in the reverse list you know the rest will pass the test.
Here's what it's suppose to look like. You should try to figure out how to do odds yourself.
function isListPalindrome(l) {
let curr = l;
let arr = [];
if (l == null)
return true;
// push all elements of l into the stack.
// a stack in JS is an array.
while(curr != null){
arr.push(curr.value);
// move ahead:
curr = curr.next;
}
let curr2 = l;
let length = arr.length;
// Traverse the list again & check by popping from the stack:
while(curr2 != null){
// get the top most element on the stack:
let lastNum = arr.pop();
// check if the node data isn't the same as the element popped:
if (curr2.value != lastNum){
return false;
}
// Half way point for evens
if (length / 2 === arr.length) {
return true;
}
// move ahead:
curr2 = curr2.next;
}
return true;
}
solving with pushing values to an array and then check if the array is palindromic will have S:O(N). with reversing the second half and then traversing will have S:O(1). T:O(N) is same for both:
var isPalindrome = function (head) {
let fast_pointer = head;
let slow_pointer = head;
// when fast_ppointer reaches to the tail, slow_pointer will be in the middle
while (fast_pointer && fast_pointer.next) {
fast_pointer = fast_pointer.next.next;
slow_pointer = slow_pointer.next;
}
// now, slow_pointer is in the middle and we reverse from slow_pointer till the head
let prev = null;
while (slow_pointer) {
// slow_pointer=slow_pointer.next how we iterate in linked lists.
// so make sure we keep a reference to the next iteration
temp = slow_pointer.next;
slow_pointer.next = prev;
prev = slow_pointer;
slow_pointer = temp;
}
let left = head;
let right = prev;
while (right) {
if (left.val !== right.val) {
return false;
}
left = left.next;
right = right.next;
}
return true;
};
var isPalindrome = function (head) {
let values = [];
while (head) {
values.push(head.val);
head = head.next;
}
let rev = [];
head.map((e) => {
rev.unshift(e);
});
if (values.every((val, index) => val === rev[index])) {
return true;
} else {
return false;
}
};
class Node {
constructor(value, next = null) {
this.value = value;
this.next = next;
}
}
const is_palindromic_linked_list = function (head) {
let front = head;
const traverse = (node) => {
if (!node) return true;
//reverse the LL
const reverse = traverse(node.next);
//check value if they are equal
const valChecker = front.value == node.value;
front = front.next;
return reverse && valChecker;
}
return traverse(head)
};
head = new Node(2)
head.next = new Node(4)
head.next.next = new Node(6)
head.next.next.next = new Node(4)
head.next.next.next.next = new Node(2)
console.log(`Is palindrome: ${is_palindromic_linked_list(head)}`)
head.next.next.next.next.next = new Node(2)
console.log(`Is palindrome: ${is_palindromic_linked_list(head)}`)
I push all the elements of the list in an array and then I convert the array with join function to a string so that i can compare if the string is the same as the inverse using reverse function if it is then it is a palindrome
function isListPalindrome(l) {
if(l === null) return true;
let array =[];
let current = l;
while (current != null){
array.push(current.value);
current = current.next
}
if(array.join('')=== array.reverse().join('')) return true;
return false
}

Binary Tree - Depth-First Traversal

I want to do a depth-first traversal for this binary tree:
1
/ \
4 5
/ \ \
4 4 5
Here's the node structure:
function TreeNode(data){
this.data = data
this.left = this.right = []
this.addLeft = function(node){
this.left.push(node)
}
this.addRight = function(node){
this.right.push(node)
}
}
The visit function (just to print out the node data):
function visit(node){
console.log(node.data)
}
The traverse function:
function traverse(node){
if(node === null) return
visit(node)
//visit left branch
for(node of node.left) traverse(node)
//visit right branch
for(node of node.right) traverse(node)
}
Add the binary tree structure:
let rootNode = new TreeNode(1)
let node_4A = new TreeNode(4)
let node_4B = new TreeNode(4)
let node_4C = new TreeNode(4)
let node_5A = new TreeNode(5)
let node_5B = new TreeNode(5)
//add root node branches
rootNode.addLeft(node_4A)
rootNode.addRight(node_5A)
node_4A.addLeft(node_4B)
node_4A.addRight(node_4C)
node_5A.addRight(node_5B)
The output:
1
4
4
4
5
5
5
So it correctly prints out the node data, but there's always an additional right-most node that got printed twice (i.e. the last 5). Do you have any idea why it happens?
I'm not too familiar with Javascript call stack, but could the reason be I'm running 2 for loops in a recursive function?
Thank you.
You take the same object reference for left and right.
this.left = this.right = []
You need independent arrays:
this.left = [];
this.right = [];
For taking the right node, take different names than node for iterating.
function traverse(node) {
if (!node) return; // you never have a value of null for a node
visit(node)
//visit left branch
for (let n of node.left) {
traverse(n);
}
//visit right branch
for (let n of node.right) {
traverse(n);
}
}
function TreeNode(data) {
this.data = data
this.left = [];
this.right = [];
this.addLeft = function (node) {
this.left.push(node)
}
this.addRight = function (node) {
this.right.push(node)
}
}
function visit(node) {
console.log(node.data)
}
function traverse(node) {
if (!node) return; // you never have a value of null for a node
visit(node)
for (let n of node.left) {
traverse(n);
}
for (let n of node.right) {
traverse(n);
}
}
let rootNode = new TreeNode(1)
let node_4A = new TreeNode(4)
let node_4B = new TreeNode(4)
let node_4C = new TreeNode(4)
let node_5A = new TreeNode(5)
let node_5B = new TreeNode(5)
//add root node branches
rootNode.addLeft(node_4A)
rootNode.addRight(node_5A)
node_4A.addLeft(node_4B)
node_4A.addRight(node_4C)
node_5A.addRight(node_5B)
traverse(rootNode);
DFS (depth first search) is usually easy to implement using recursion. refer to this function definition in js language -
const recFnc = (currNode) => {
if (currNode !== null) {
if (currNode.lNode !== null) {
recFnc(currNode.lNode, lPath);
}
if (currNode.rNode !== null) {
recFnc(currNode.rNode, rPath);
}
}
};
recFnc(rootNode);
Refer to this class I have created - https://www.npmjs.com/package/#dsinjs/binary-tree
and Refer to this function documentation which deals with path calculations and more - https://dsinjs.github.io/binary-tree/#find
You do this:
this.left = this.right = []
So the left leaf is actually the same as the right one. You want:
this.left = [];
this.right = [];
Just for fun: This would actually be a good usecase for generators:
TreeNode.prototype.leftFirst = function*() {
yield this.data;
for(const child of this.left.concat(this.right))
yield* child.leftFirst();
};
So you can do:
for(const node of tree.leftFirst())
console.log(node);

strategies to reverse a linked list in JavaScript

I just struggled through a simple interview question: Please reverse a singly linked list.
While I failed to provide a working answer in time to save the interview, I was able to come up with a solution afterwards.
Is my solution correct? How would you analyze this with Big-Oh? Are there more efficient ways to reverse a singly linked list?
// reverse a linked list
var reverseLinkedList = function(linkedlist) {
var node = linkedlist;
var previous = null;
while(node) {
// reverse pointer
node.next = previous;
// increment previous to current node
previous = node;
// increment node to next node
if (node.next){
node = node.next
} else {
node = null;
}
}
}
Note: In my search for similar posts, I did find one example in JavaScript. I was wondering if my code is possible (without a temp variable). Thank you.
There are a couple of problems with your code. This should make it clear.
// reverse a linked list
var reverseLinkedList = function(linkedlist) {
var node = linkedlist;
var previous = null;
while(node) {
// save next or you lose it!!!
var save = node.next;
// reverse pointer
node.next = previous;
// increment previous to current node
previous = node;
// increment node to next node or null at end of list
node = save;
}
return previous; // Change the list head !!!
}
linkedlist = reverseLinkedList(linkedlist);
You could solve this problem recursively in O(n) time as ckersch mentions. The thing is, that you need to know that recursion is memory intensive since functions accumulate in the calls stack until they hit the stop condition and start returning actual things.
The way I'd solve this problem is:
const reverse = (head) => {
if (!head || !head.next) {
return head;
}
let temp = reverse(head.next);
head.next.next = head;
head.next = undefined;
return temp;
}
When reverse() reaches the end of the list, it will grab the last node as the new head and reference each node backwards.
This would be O(n) in time, since you do a constant number of operations on each node. Conceptually, there isn't a more efficient way of doing things (in terms of big-O notation, there's some code optimization that could be done.)
The reason why you can't exceed O(n) is because, in order to do so, you would need to skip some nodes. Since you need to modify each node, this wouldn't be possible.
Efficiency then comes down to a constant factor. The fewer operations you can do per item in the list, the faster your code will execute.
I'd implement like this:
function reverseLinkedList(list, previous){
//We need to use the the current setting of
//list.next before we change it. We could save it in a temp variable,
//or, we could call reverseLinkedList recursively
if(list.next !== null){
reverseLinkedList(list.next, list);
}
//Everything after 'list' is now reversed, so we don't need list.next anymore.
//We passed previous in as an argument, so we can go ahead and set next to that.
list.next = previous;
}
reverseLinkedList(list, null);
Of course, this is recursive, so it would be inefficient in terms of space, but I like recursive code :)
This also doesn't return the reversed linked list, but we could fairly easily modify things to do so if that were important.
ES6 solution:
Just keep a track of the reversed list and keep adding that to tmp.
const reverseLinkedList = (head) => {
let reversed = null;
while(head) {
const tmp = head;
head = head.next;
tmp.next = reversed;
reversed = tmp;
}
return reversed;
};
console.log(JSON.stringify(reverseLinkedList({
data: 1,
next: {
data: 2,
next: {
data: 3,
next: {
data: 4,
next: {
data: 5,
next: {
data: 5,
next: {
data: 6
}
}
}
}
}
}
})));
Reversing the SinglyLinkedList:
Input: 1->2->3->4->5->NULL
Output: 5->4->3->2->1->NULL
To understand The Solution we have to keep track of previous head and next variables
for example in above input Head = 1 ; next = 2 we don't have previous so assume previous = null
loop the list till head is not null. reverse the connections(previous and next) of head.
Below is the code
var reverseList = function(head) {
let previous = null;
while(head !== null){
let next = head.next;
head.next = previous;
previous= head
head = next;
}
return previous;
};
//O(n) | O(1) wherre n is the number of nodes in the linked list
class Node{
constructor(val){
this.val = val;
this.next = null;
}
}
function reverseLinkedList(head) {
if(!head) return null;
let p1 = head;
let p2 = null;
while(p1){
let temp = p1.next;
p1.next = p2;
p2 = p1;
p1 = temp;
}
return p2;
}
const a = new Node(1);
a.next = new Node(2);
a.next.next = new Node(3)
console.log("Current Node",a);
console.log("Reversed List",reverseLinkedList(a))
class LinkedList {
constructor () {
this.head = this.tail = null
}
// add to the end of the list
append (value) {
if (!this.tail) {
this.head = this.tail = new Node(value)
} else {
let oldTail = this.head
this.head = new Node(value)
this.head.next = oldhead
}
}
reverseList() {
//your code here
let currentNode = this.head
this.head = null
while(currentNode) {
if (!this.head) {
this.head = new Node(currenthead.data)
} else {
let oldhead = this.head
this.head = new Node(currentNode.data)
this.head.next = oldhead
}
currentNode = currentNode.next
}
}
}
class Node {
constructor (value, next) {
this.data = value
this.next = next || null
}
}
const list = new LinkedList()
list.append(1)
list.append(2)
list.reverseList()
Since inserting data at the beginning of the linked list pushes other first nodes till the end, and since it's a O(1) process.
Then I created the following function reverse()
where it basically insert node elements in the beginning which basically will get a reversed list at the end.
Here's a demo down below:
class Node {
constructor(data, next = null) {
this.data = data;
this.next = next;
}
}
class LinkedList {
constructor() {
this.head = null;
this.size = 0;
}
insertFirst(data = null) {
// make new head point to the previous head
this.head = new Node(data, this.head);
this.size ++;
}
insertLast(data = null) { // insert last in the beginning will be the first in the linked list
const node = new Node(data);
// If empty, insert first
if (!this.head) this.insertFirst(data);
else {
let current = this.head;
// while next is not null, continue
while (current.next)
current = current.next;
// eventually next is null, we want to set next here to the node we want to add
current.next = node;
}
this.size ++;
}
// print linked list
print() {
let current = this.head;
let output = "";
while (current) { // while current is not null, eventually it will be null
output += current.data + " => ";
current = current.next; // current jumping to the next node
}
output += "| NULL"; // ending
console.log(output);
return output;
}
reverse() {
if (!this.head) return; // if no head, do nothing
let current = this.head;
const linkedList = new LinkedList(); // create a new linked list
// don't worry, it will be garbage collected once this function ends since it's not a global variable
while (current) {
linkedList.insertFirst(current.data); // insert first at the beginning will be the end of the linked list at the end
current = current.next;
}
// assign current head to the reversed linked list head
this.head = linkedList.head;
}
}
const linkedList = new LinkedList();
// fill data as 100 -> 200 -> 300 -> 400
linkedList.insertLast(100);
linkedList.insertLast(200);
linkedList.insertLast(300);
linkedList.insertLast(400);
// To view results
const bodyElement = document.getElementsByTagName("body")[0];
bodyElement.innerHTML = `<p>Original Linked List: <b>${linkedList.print()}</b></p>`; // 100 200 300 400
linkedList.reverse();
bodyElement.innerHTML += `<p>Reversed Linked List: <b>${linkedList.print()}</b></p>`; // 400 300 200 100
b {
color: green;
}
<body></body>
Overall, the whole process of this reverse() function is O(n).
Hopefully this sounds clear to you, and correct me if I'm wrong.
This is my recursive solution:
https://codesandbox.io/s/reverse-linked-list-tqh2tq?file=/src/index.js
let d = { me: "d" };
let c = { me: "c", next: d };
let b = { me: "b", next: c };
let a = { me: "a", next: b };
const reverseMe = (o) => {
let lastDude;
if (o.next.next) lastDude = reverseMe(o.next);
else lastDude = o.next;
o.next.next = o;
o.next = null;
return lastDude;
};
console.log("result", reverseMe(a));

Categories