/* SinglyLinkedList!! * A linked list is similar to an array, it holds a list of values. * However, links in a linked list do not have indexes. With * a linked list you do not need to predetermine its size as * it grows and shrinks as it is edited. This is an example of * a singly linked list. */ // Methods - size, head, addLast, addFirst, addAt, removeFirst, removeLast, remove, removeAt, indexOf, isEmpty, elementAt, findMiddle, get, clean, rotateListRight class Node { constructor (data) { this.data = data this.next = null } } class LinkedList { constructor (listOfValues) { this.headNode = null this.length = 0 if (listOfValues instanceof Array) { for (const value of listOfValues) { this.addLast(value) } } } // initiates the currentNode and currentIndex and return as an object initiateNodeAndIndex () { return { currentNode: this.headNode, currentIndex: 0 } } // Returns length size () { return this.length } // Returns the head head () { return this.headNode?.data || null } // Return if the list is empty isEmpty () { return this.length === 0 } // add a node at last it to linklist addLast (element) { // Check if its the first element if (this.headNode === null) { return this.addFirst(element) } let { currentNode } = this.initiateNodeAndIndex() // Loop till there is a node present in the list while (currentNode.next) { currentNode = currentNode.next } const node = new Node(element) // Adding node at the end of the list and increase the length currentNode.next = node this.length++ return this.size() } // add a node at first it to linklist addFirst (element) { const node = new Node(element) node.next = this.headNode this.headNode = node this.length++ return this.size() } // remove the first from the linklist removeFirst () { const removedNode = this.headNode if (this.length > 0) { this.headNode = this.headNode.next this.length-- } return removedNode?.data } // remove the last from the linklist removeLast () { if (this.isEmpty()) return null if (this.length === 1) { return this.removeFirst() } let { currentIndex, currentNode } = this.initiateNodeAndIndex() while (currentIndex !== this.length - 2) { currentIndex++ currentNode = currentNode.next } const removedNode = currentNode.next currentNode.next = null this.length-- return removedNode.data } // Removes the node with the value as param remove (element) { if (this.isEmpty()) return null let { currentNode } = this.initiateNodeAndIndex() let removedNode = null // Check if the head node is the element to remove if (currentNode.data === element) { return this.removeFirst() } // Check which node is the node to remove while (currentNode?.next) { if (currentNode.next.data === element) { removedNode = currentNode.next currentNode.next = currentNode.next.next this.length-- break } currentNode = currentNode.next } return removedNode?.data || null } // Returns the index of the element passed as param otherwise -1 indexOf (element) { let { currentIndex, currentNode } = this.initiateNodeAndIndex() while (currentNode) { // Checking if the node is the element we are searching for if (currentNode.data === element) { return currentIndex } currentNode = currentNode.next currentIndex++ } return -1 } // Returns the element at an index elementAt (index) { if (index >= this.length || index < 0) { throw new RangeError('Out of Range index') } let { currentIndex, currentNode } = this.initiateNodeAndIndex() while (currentIndex < index) { currentIndex++ currentNode = currentNode.next } return currentNode.data } // Adds the element at specified index addAt (index, element) { // Check if index is out of bounds of list if (index > this.length || index < 0) { throw new RangeError('Out of Range index') } if (index === 0) return this.addFirst(element) if (index === this.length) return this.addLast(element) let { currentIndex, currentNode } = this.initiateNodeAndIndex() const node = new Node(element) while (currentIndex !== index - 1) { currentIndex++ currentNode = currentNode.next } // Adding the node at specified index const tempNode = currentNode.next currentNode.next = node node.next = tempNode // Incrementing the length this.length++ return this.size() } // Removes the node at specified index removeAt (index) { // Check if index is present in list if (index < 0 || index >= this.length) { throw new RangeError('Out of Range index') } if (index === 0) return this.removeFirst() if (index === this.length) return this.removeLast() let { currentIndex, currentNode } = this.initiateNodeAndIndex() while (currentIndex !== index - 1) { currentIndex++ currentNode = currentNode.next } const removedNode = currentNode.next currentNode.next = currentNode.next.next // Decrementing the length this.length-- return removedNode.data } // Returns a reference to middle node of linked list findMiddle () { // If there are two middle nodes, return the second middle node. let fast = this.headNode let slow = this.headNode while (fast !== null && fast.next !== null) { fast = fast.next.next slow = slow.next } return slow } // make the linkedList Empty clean () { this.headNode = null this.length = 0 } // Method to get the LinkedList get () { const list = [] let { currentNode } = this.initiateNodeAndIndex() while (currentNode) { list.push(currentNode.data) currentNode = currentNode.next } return list } // Method for Rotating a List to the right by k places rotateListRight (k) { let i = 0 let current = this.headNode while (current) { i++ current = current.next } k %= i current = this.headNode let prev = null while (k--) { if (!current || !current.next) { return current } else { while (current.next) { prev = current current = current.next } prev.next = current.next current.next = this.headNode this.headNode = current } } } // Method to iterate over the LinkedList iterator () { let { currentNode } = this.initiateNodeAndIndex() if (currentNode === null) return -1 const iterate = function * () { while (currentNode) { yield currentNode.data currentNode = currentNode.next } } return iterate() } // Method to log the LinkedList log () { console.log(JSON.stringify(this.headNode, null, 2)) } // Method to reverse the LinkedList reverse () { let head = this.headNode let prev = null let next = null while (head) { next = head.next head.next = prev prev = head head = next } this.headNode = prev }; } export { Node, LinkedList }