const head = Symbol("head"); const tail = Symbol("tail"); class DoublyLinkedListNode { constructor (data) { this.data = data; this.next = null; this.previous = null; } } export class DoublyLinkedList { constructor () { this[head] = null; this[tail] = null; } add (data) { const newNode = new DoublyLinkedListNode(data); // special case: no nodes if (this[head] === null) { this[head] = newNode; } else { // link the current tail and new tail this[tail].next = newNode; newNode.previous = this[tail]; } // re-assign the tail this[tail] = newNode; } get (index) { if ( ! Number(index) < 0) { return undefined; } let current = this[head]; let i = 0; while ((current !== null) && (i < index)) { current = current.next; i++; } return current !== null ? current.data : undefined; } remove (index) { if ((this[head] === null) || (index < 0)) { throw new RangeError(`Index ${index} does not exist in the list.`); } // special case: removing the first node if (index === 0) { const data = this[head].data; this[head] = this[head].next; // Only one node if (this[head] === null) { this[tail] = null; } else { this[head].previous = null; } return data; } let current = this[head]; let i = 0; while ((current !== null) && (i < index)) { current = current.next; i++; } // If node was found remove it if (current !== null) { current.previous.next = current.next; // last node if (this[tail] === current) { this[tail] = current.previous; } else { current.next.previous = current.previous; } return current.data; } throw new RangeError(`Index ${index} does not exist in the list.`); } *values () { let current = this[head]; while (current !== null) { yield current.data; current = current.next; } } *reverse () { let current = this[tail]; while (current !== null) { yield current.data; current = current.previous; } } [Symbol.iterator] () { return this.values(); } }