Input: 5 -> 9 -> 8 -> 3 -> 1 -> 7
Expected Output: 7 -> 1 -> 3 -> 8 -> 9 -> 5
Issue:
When I display the reversed linked list the result is 5. This is an issue because this should be the tail and not the head. The rest of the nodes are missing in the display well.
Question:
Is there an issue with the code base that is preventing the traversal from the head to the tail and changing the pointers to reverse the list?
Code:
LinkedList:
class LinkedList {
constructor() {
this.head = null;
this.size = 0;
}
insertFirst(item) {
if (this.head !== null) {
const newHead = new _Node(item);
let oldHead = this.head;
oldHead.prev = newHead;
newHead.next = oldHead;
this.head = newHead;
} else {
this.head = new _Node(item, this.head);
}
this.size++;
}
insertLast(item) {
if (!this.head) {
this.insertFirst(item);
} else {
let tempNode = this.head;
while (tempNode.next !== null) {
tempNode = tempNode.next;
}
tempNode.next = new _Node(item, null, tempNode);
}
this.size++
}
}
module.exports = LinkedList;
Main:
const LinkedList = require("./LinkedLists");
const { reverse } = require("./Reverse");
const { display } = require("./Supplemental");
function main() {
let SLL = new LinkedList();
SLL.insertFirst(5);
SLL.insertLast(9);
SLL.insertLast(8);
SLL.insertLast(3);
SLL.insertLast(1);
SLL.insertLast(7);
reverse(SLL);
display(SLL);
return SLL;
}
console.log(main());
Reverse:
reverse = (SLL) => {
let curr = SLL.head
if (!curr) {
return;
}
if (!curr.next) {
SLL.head = curr;
return;
}
let tmp = reverse(curr.next);
curr.next.next = curr;
curr.next = null;
return tmp;
}
module.exports = { reverse };
Display:
display = (SLL) => {
let currentNode = SLL.head;
if (!SLL.head) {
return null;
}
while (currentNode !== null) {
console.log(currentNode.value);
currentNode = currentNode.next;
}
return;
};
Can someone tell me what return tmp is doing in the Reverse.js file?
(1) Removed display from Main.js
(2) Edited Main.js:
const LinkedList = require("./LinkedLists");
const { reverse } = require("./Reverse");
const { display } = require("./Supplemental");
function main() {
let SLL = new LinkedList();
SLL.insertFirst(5);
SLL.insertLast(9);
SLL.insertLast(8);
SLL.insertLast(3);
SLL.insertLast(1);
SLL.insertLast(7);
const result = reverse(SLL.head);
console.log(result);
return SLL;
}
return main();
(3) Edited Reverse.js:
reverse = (curr, prev = null) => {
if (!curr) {
return prev;
}
let tmp = reverse(curr.next, curr);
const temp = curr.next;
curr.next = prev;
curr.prev = temp;
return tmp;
}
module.exports = { reverse };
Related
I have a few classes to make a linked list of books. I am having a hard time alphabetically sorting each book and returning them all. I haven't found anything on SO related to sorting linked lists alphabetically in JavaScript specifically so hopefully this post example will be useful for others too. The sortList() function should sort the books alphabetically by their name and return them all so they can be console.log'd.
class Book {
constructor(element) {
this.element = element;
this.next = null;
}
}
class Books {
constructor() {
this.head = null;
this.size = 0;
}
add(element) { //adds a book
var node = new Book(element);
var current;
if (this.head == null) this.head = node;
else {
current = this.head;
while (current.next) {
current = current.next;
}
current.next = node;
}
this.size++;
}
insertAt(element, index) { //adds a book at the specified index
if (index < 0 || index > this.size)
return console.log("Please enter a valid index.");
else {
var node = new Book(element);
var curr, prev;
curr = this.head;
if (index == 0) {
node.next = this.head;
this.head = node;
} else {
curr = this.head;
var it = 0;
while (it < index) {
it++;
prev = curr;
curr = curr.next;
}
node.next = curr;
prev.next = node;
}
this.size++;
}
}
sortList() { //sorts the head alphabetically
var sortedList = new Books();
let current = this.head;
var array = new Set();
while (current != null) {
array.add(current);
current = current.link;
}
array.sort();
for (let i = array.length - 1; i >= 0; i--) {
sortedList.insertAt(new Book(array[i]), 0);
}
return sortedList;
}
}
var bookList = new Books();
bookList.add("abook1");
bookList.add("bbook2");
bookList.add("cbook3");
bookList.add("dbook4");
bookList.add("ebook5");
bookList.add("fbook6");
bookList.add("gbook7");
bookList.add("hbook8");
console.log(bookList.sortList()); //prints out the sorted bookList
As an alternative solution, here is a merge sort algorithm, which has a time complexity of O(nlogn):
class Book {
constructor(element) {
this.element = element;
this.next = null;
}
}
class Books {
constructor() {
this.head = null;
this.size = 0;
}
add(element) { //adds a book
var node = new Book(element);
var current;
if (this.head == null) this.head = node;
else {
current = this.head;
while (current.next) {
current = current.next;
}
current.next = node;
}
this.size++;
}
*values() { // Utility function to facilitate printing
let current = this.head;
while (current) {
yield current.element;
current = current.next;
}
}
sortList() { // Sorts the list alphabetically, using merge sort
if (!this.head || !this.head.next) return; // Nothing to sort
// Find last node of first half
let node = this.head;
for (let fast = node.next; fast?.next; fast = fast.next.next) {
node = node.next;
}
// Split list into two halves
let that = new Books();
that.head = node.next;
node.next = null;
// Recursively sort the two shorter lists
this.sortList();
that.sortList();
// Merge the two sorted lists
if (this.head.element > that.head.element) [this.head, that.head] = [that.head, this.head];
let prev = this.head;
let thatNode = that.head;
while (prev.next && thatNode) {
if (prev.next.element > thatNode.element) [thatNode, prev.next] = [prev.next, thatNode];
prev = prev.next;
}
if (thatNode) prev.next = thatNode;
// The sort happened in-place, so we don't return the list
}
}
let bookList = new Books();
for (let ch of "himvlxpbcyndwjkefuzgqorsat") {
bookList.add(ch);
}
console.log("input:");
console.log(...bookList.values());
bookList.sortList();
console.log("sorted:");
console.log(...bookList.values());
Comparison of running times.
Here is a comparison between algorithms, using a list of 500 elements, sorted initially in reversed order: "499", "498", "497", ..., "001", "000".
const
compareString = (a, b) => a.localeCompare(b);
class Book {
constructor(element) {
this.element = element;
this.next = null;
}
}
class Books {
constructor() {
this.head = null;
this.size = 0;
}
add(element) { //adds a book
var node = new Book(element);
var current;
if (this.head == null) this.head = node;
else {
current = this.head;
while (current.next) {
current = current.next;
}
current.next = node;
}
this.size++;
}
sortList_NinaScholz() { // Version of 20.10.2021
let current = this.head;
while (current.next) {
if (compareString(current.element, current.next.element) > 0) { // swap
[current.element, current.next.element] = [current.next.element, current.element];
current = this.head;
continue;
}
current = current.next;
}
return this;
}
sortList_trincot() {
if (!this.head?.next) return; // Nothing to sort
// Find last node of first half
let node = this.head;
for (let fast = node.next; fast?.next; fast = fast.next.next) {
node = node.next;
}
// Split list into two halves
let that = new Books();
that.head = node.next;
node.next = null;
// Recursively sort the two shorter lists
this.sortList_trincot();
that.sortList_trincot();
// Merge the two sorted lists
if (this.head.element > that.head.element) [this.head, that.head] = [that.head, this.head];
let prev = this.head;
let thatNode = that.head;
while (prev.next && thatNode) {
if (prev.next.element > thatNode.element) [thatNode, prev.next] = [prev.next, thatNode];
prev = prev.next;
}
if (thatNode) prev.next = thatNode;
// The sort happened in-place, so we don't return the list
}
}
console.log("running sort...");
setTimeout(function () {
for (let method of ["trincot", "NinaScholz"]) {
let bookList = new Books();
for (let v of [...Array(500).keys()].reverse())
bookList.add(v.toString().padStart(3, "0"));
let start = performance.now();
bookList["sortList_" + method]();
console.log(method, performance.now() - start, "milliseconds");
// verify that list is really sorted
for (let book = bookList.head, i=0; book; book = book.next, i++) {
if (+book.element != i) throw "not well sorted";
}
}
}, 100);
You could change the values from the liked list by checking node and the next node. If necessary swap the values and start the comparing again from head.
This approach takes a comparing function which uses a three-way comparison with a return value of smaller than zero, zero or greater than zero, depending on the order.
const
compareString = (a, b) => a.localeCompare(b);
class Book {
constructor(element) {
this.element = element;
this.next = null;
}
}
class Books {
constructor() {
this.head = null;
this.size = 0;
}
add(element) { //adds a book
var node = new Book(element);
var current;
if (this.head == null) this.head = node;
else {
current = this.head;
while (current.next) {
current = current.next;
}
current.next = node;
}
this.size++;
}
sortList() {
let current = this.head;
while (current.next) {
if (compareString(current.element, current.next.element) > 0) { // swap
[current.element, current.next.element] = [current.next.element, current.element];
current = this.head;
continue;
}
current = current.next;
}
return this;
}
}
var bookList = new Books();
bookList.add("ac");
bookList.add("ab");
bookList.add("cc");
bookList.add("bb");
bookList.add("aa");
bookList.add("dd");
bookList.add("ba");
bookList.add("bc");
console.log(bookList.sortList()); //prints out the sorted bookList
I have the following class ListNode
class ListNode {
constructor(val) {
this.val = val
this.next = null
}
}
I am trying to delete repeat values by storing the values in a hash, and if those values are present, then the new Node should not be formed with those values; however, all I am accomplishing is a copy of the present list. I am not sure what I am doing wrong within my hash. Am I structuring the logic incorrectly?
const deleteDuplicates = (head) => {
let newNode = new ListNode('dummy')
let current = newNode
let headHash = {}
while (head) {
if (headHash[head.val] === undefined) {
if (newNode.next === null) newNode.next = new ListNode(head.val)
else {
newNode = newNode.next
newNode.next = new ListNode(head.val)
}
}
headHash = (headHash[head.val] || 0) + 1
console.log(headHash, head.val);
head = head.next
}
return current.next
}
const l = new ListNode(1)
l.next = new ListNode(1)
l.next.next = new ListNode(2)
const l2 = new ListNode(1)
l2.next = new ListNode(1)
l2.next.next = new ListNode(2)
l2.next.next.next = new ListNode(3)
l2.next.next.next.next = new ListNode(3)
console.log(deleteDuplicates(l));
console.log(deleteDuplicates(l2));
The offending line seems to be this one:
headHash = (headHash[head.val] || 0) + 1
Instead of assigning the whole headHash to a value, you'll have to assign the headHash's current head value property to a not undefined value. See the code below:
class ListNode {
constructor(val) {
this.val = val;
this.next = null;
}
}
const deleteDuplicates = (head) => {
let newNode = new ListNode("dummy");
let current = newNode;
let headHash = {};
while (head) {
if (headHash[head.val] === undefined) {
if (newNode.next === null) {
newNode.next = new ListNode(head.val);
} else {
newNode = newNode.next;
newNode.next = new ListNode(head.val);
}
}
// headHash = (headHash[head.val] || 0) + 1 // <- offending line
headHash[head.val] = (headHash[head.val] || 0) + 1; // You need to assign the value to the headHash's key, not to the headHasn itself.
head = head.next;
}
return current.next;
};
const l = new ListNode(1);
l.next = new ListNode(1);
l.next.next = new ListNode(2);
const l2 = new ListNode(1);
l2.next = new ListNode(1);
l2.next.next = new ListNode(2);
l2.next.next.next = new ListNode(3);
l2.next.next.next.next = new ListNode(3);
console.log(deleteDuplicates(l));
console.log(deleteDuplicates(l2));
I'd like to re-factor Cache class purely for academic reason.
However, I'm having a tough time figuring out how I can move getMap out of the Cache class and have it as a regular function.
function isObject(arg) {
const typeOfObj = typeof arg;
return (typeOfObj === 'object' || typeOfObj === 'function') && arg !== null;
}
class Cache {
constructor() {
this.map = new Map();
this.weakmap = new WeakMap();
}
// return a Cache's value at a key
getMap(key) {
// console.log(this);
const map = this[isObject(key) ? 'weakmap' : 'map'];
// console.log(map);
this.setKeyIfNeeded(map, key);
let valueMap = map.get(key);
return valueMap;
}
// create a Cache's key, if needed
setKeyIfNeeded(map, key) {
if (!map.has(key)) {
map.set(key, new Cache());
}
}
}
const getNestedMap = (keys, initialCache) =>
keys.reduce((cache, key) => cache.getMap(key), initialCache);
function memoize(fn) {
const cache = new Cache();
return (...args) => {
// get (or create) a cache item
const item = getNestedMap(args, cache);
if (Reflect.has(item, 'value')) {
return item.value;
}
return (item.value = fn(args));
};
}
let counter = 1;
function foo() {
counter += 1;
return counter;
}
const id1 = Symbol('id');
const id2 = Symbol('id');
const memoizedFoo = memoize(foo);
console.log(memoizedFoo(3, 4, 5, 6)); //2
console.log(memoizedFoo(3, 4, 5, 6)); //2
console.log(memoizedFoo(3, 4, 6)); //3
console.log(memoizedFoo(3, 4, 6)); //3
You will need to rewrite your function to accept all things. Then you'd just call it from within your class.
One example might be:
getMap(cache, key, isObject, setKeyIfNeeded) {
// console.log(this);
const map = cache[isObject(key) ? 'weakmap' : 'map'];
// console.log(map);
setKeyIfNeeded(map, key);
let valueMap = map.get(key);
return valueMap;
}
SOLUTION
function isObject(arg) {
const typeOfObj = typeof arg;
return (typeOfObj === 'object' || typeOfObj === 'function') && arg !== null;
}
class Cache {
constructor() {
this.map = new Map();
this.weakmap = new WeakMap();
}
static setKey(key, map) {
return map.set(key, new Cache());
}
}
function getCache(args, cache) {
for (const key of args) {
const map = cache[isObject(key) ? 'weakmap' : 'map'];
cache = map.get(key) || Cache.setKey(key, map).get(key);
}
return cache;
}
function memoize(fn) {
const cache = new Cache();
return (...args) => {
const item = getCache(args, cache);
if (Reflect.has(item, 'value')) {
return item.value;
}
return (item.value = fn(args));
};
}
let counter = 1;
function foo() {
counter += 1;
return counter;
}
This is my implementation of a graph, to get the shortest path between A and B.
class Queue {
constructor() {
this.head = null;
this.tail = null;
this.size = 0;
}
offer(item) {
const p = new QueueNode(item);
this.size++;
if (this.head === null) {
this.head = p;
this.tail = p;
return;
}
this.tail.next = p;
this.tail = p;
}
poll() {
if (this.size === 0) {
throw TypeError("Can't deque off an empty queue.");
}
this.size--;
const item = this.head;
this.head = this.head.next;
return item.val;
}
peek() {
if (this.size === 0) {
throw TypeError("Empty Queue.")
}
return this.head.val;
}
isEmpty() {
return this.head === null;
}
}
class QueueNode {
constructor(item) {
this.val = item;
this.next = null;
}
}
class Graph {
constructor(directed = false) {
this.numVertices = 0;
this.directed = directed;
this.dict = {}
}
addEdge(v1, v2, weight = 1) {
let p, q;
if (v1 in this.dict) {
p = this.dict[v1];
} else {
p = new GraphNode(v1);
this.dict[v1] = p;
this.numVertices++;
}
if (v2 in this.dict) {
q = this.dict[v2];
} else {
q = new GraphNode(v2);
this.dict[v2] = q;
this.numVertices++;
}
p.addEdge(q);
if (!this.directed) {
q.addEdge(p);
}
}
stringify() {
for (const [key, value] of Object.entries(this.dict)) {
console.log(`${key}: ${[...value.adjacencySet].map(x => x.data)}`);
}
}
buildDistanceTable(source) {
let p;
if (this.dict[source] === undefined) {
throw TypeError('Vertex not present in graph')
} else {
p = this.dict[source];
}
const distanceTable = {};
for (const [key, value] of Object.entries(this.dict)) {
distanceTable[key] = [-1, -1];
}
distanceTable[p.data] = [0, p.data];
const queue = new Queue();
queue.offer(p);
while (!queue.isEmpty()) {
let curr = queue.poll();
let curr_distance = distanceTable[curr.data][0];
curr.adjacencySet.forEach((item) => {
if (distanceTable[item.data] === -1) {
distanceTable[item.data] = [1 + curr_distance, curr.data];
console.log(distanceTable);
if (item.adjacencySet.length > 0) {
queue.offer(item);
}
}
})
}
return distanceTable;
}
shortestPath(source, destination) {
const distanceTable = this.buildDistanceTable(source);
const path = [destination];
let prev = distanceTable[destination][1];
while (prev !== -1 && prev !== source) {
path.unshift(prev);
prev = distanceTable[prev][1];
}
if (prev === null) {
console.log("There's no path from source to destination");
} else {
path.unshift(source);
path.map(item => {
console.log(item);
});
}
}
}
class GraphNode {
constructor(data) {
this.data = data;
this.adjacencySet = new Set();
}
addEdge(node) {
this.adjacencySet.add(node)
}
}
graph = new Graph(directed = false);
graph.addEdge(0, 1);
graph.addEdge(1, 2);
graph.addEdge(1, 3);
graph.addEdge(2, 3);
graph.addEdge(1, 4);
graph.addEdge(3, 5);
graph.addEdge(5, 4);
graph.addEdge(3, 6);
graph.addEdge(6, 7);
graph.addEdge(0, 7);
graph.stringify();
graph.shortestPath(1, 7);
When I run this it give 1, 7 however that's not the shortest path. What am I doing wrong here.
You have 2 issue in your code (that sabotage the building of the distance table):
You missing index in: if (distanceTable[item.data] === -1) { -> each item in the distance table is of array therefor it need to be: if (distanceTable[item.data][0] === -1) {
Set size in node js checked with size and not length (as in documentation) therefor item.adjacencySet.length is always undefined so you need to change: if (item.adjacencySet.length> 0) { to if (item.adjacencySet.size > 0) {
After those 2 changes your code return me path of 1 -> 0 -> 7
Just small side issue: you missing some ; and "new" before throwing TypeError...
I am trying to write the algorithm to convert a BST to a doubly linked list. This is what I have so far. Below is the code:
function TreeNode(val) {
this.val = val;
this.left = this.right = null;
}
function BinaryTree() {
this.root = null;
}
BinaryTree.prototype.push = function(val) {
var root = this.root;
if(!root) {
this.root = new TreeNode(val);
return;
}
var currentNode = root;
var newNode = new TreeNode(val);
while(currentNode) {
if (val < currentNode.val) {
if(!currentNode.left) {
currentNode.left = newNode;
break;
} else {
currentNode = currentNode.left;
}
} else if(val > currentNode.val) {
if(!currentNode.right) {
currentNode.right = newNode;
break;
} else {
currentNode = currentNode.right;
}
}
}
}
var bt = new BinaryTree();
bt.push(4);
bt.push(2);
bt.push(5);
bt.push(1);
bt.push(3);
//console.log(bt);
//var node = bt.root;
function Node(node) {
//this.data = value;
//this.previous = this.next = null;
var head = null;
var tail = null;
var prev = null;
console.log(bstToLL(node, head, prev, tail));
}
//function DoublyLinkedList() {
// this.head = null;
// this.prev = null;
// this.tail = null;
//}
function bstToLL(node, head, prev, tail) {
if (node === null) {
return;
}
bstToLL(node.left, head, prev, tail);
if (head === null) {
head = node;
//console.log(head)
}
if (prev === null) {
prev = node;
//console.log(prev)
} else {
//console.log(node);
//console.log(prev);
node.left = prev;
prev.right = node;
}
prev = node
bstToLL(node.right, head, prev, tail);
if(node.right === null) {
tail = node;
}
return head;
}
Node(bt.root);
The code works, but I don't think it is getting the right result. The binary tree looks like-
4
/ \
2 5
/ \
1 3
When I return the head from the bstToLL() method, I get an object with val 4 pointing to right child 5 and left child 2 and so on and so forth.
If you run the code, and check the debugger you will see the head object.
Can someone please guide me if I am doing this the right way, and how to fix the result?
Here is some code which converts a binary tree into a LinkedList. It will log 1, 2, 3, 4, and 5, in order:
function TreeNode(left, value, right) {
this.left = left;
this.value = value;
this.right = right;
}
function ListNode(prev, value, next) {
this.prev = prev;
this.value = value;
this.next = next;
}
function LinkedList(head, tail) {
if (tail === undefined) tail = head;
this.head = head;
this.tail = tail;
}
LinkedList.prototype.addToStart = function(list) {
this.head.prev = list.tail;
list.tail.next = this.head;
this.head = list.head;
}
LinkedList.prototype.addToEnd = function(list) {
this.tail.next = list.head;
list.head.prev = this.tail;
this.tail = list.tail;
};
function bstToLL(tree) {
var centerNode = new ListNode(null, tree.value, null);
var list = new LinkedList(centerNode);
if (tree.left) list.addToStart(bstToLL(tree.left));
if (tree.right) list.addToEnd(bstToLL(tree.right));
return list;
}
var tree = new TreeNode(
new TreeNode(
new TreeNode(null, 1, null),
2,
new TreeNode(null, 3, null)
),
4,
new TreeNode(null, 5, null)
);
var linkedList = bstToLL(tree);
for (var node = linkedList.head; node; node = node.next) console.log(node.value);