UNPKG

@node-dlc/core

Version:
112 lines (94 loc) 2.62 kB
import { LinkedListNode } from './LinkedListNode'; /** * Implementation of a doubly linked-list that maintains both head and tail. * Tail maintenance allows for O(1) insertions at tail */ export class LinkedList<T> { public length = 0; public head: LinkedListNode<T> = null; public tail: LinkedListNode<T> = null; /** * Adds a node to the end of a linked List * @param T value * @returns {LinkedListNode} */ public add(value: T): LinkedListNode<T> { const node = new LinkedListNode(value); // when empty list if (!this.head) { this.head = node; this.tail = node; this.length++; return node; } // non-empty, append to tail node.prev = this.tail; this.tail.next = node; this.tail = node; this.length++; return node; } /** * Finds the node at a specific position */ public valueAt(index: number): T { const node = this.nodeAt(index); if (node) return node.value; } /** * Finds the node for the index or throws an out of range exception */ public nodeAt(index: number): LinkedListNode<T> { // error when index out of range if (index < 0 || index > this.length) { throw new RangeError('Index out of range'); } // seek until index is found let currentNode = this.head; let count = 0; while (count < index) { currentNode = currentNode.next; count++; } return currentNode; } /** * Removes the node at the index and returns its value. * Head or tail removal is an O(1) operation. For removal of other indexes * is at worst O(N). */ public remove(index: number): T { // error when index out of range if (index < 0 || index > this.length) { throw new RangeError('Index out of range'); } let removeNode; let prevNode = null; let nextNode = null; // first node simply removes the node at the tip if (index === 0) { removeNode = this.head; nextNode = this.head.next; // adjust head this.head = nextNode; } // last node, update the tail and mark next as null if (index === this.length - 1) { removeNode = this.tail; prevNode = this.tail.prev; // adjust tail this.tail = prevNode; } // middle node if (!removeNode) { removeNode = this.nodeAt(index); prevNode = removeNode.prev; nextNode = removeNode.next; } // splice out the node afer null checking if (prevNode) prevNode.next = nextNode; if (nextNode) nextNode.prev = prevNode; this.length--; return removeNode.value; } }