export class LinkedListNode { public removed = false; public left: LinkedListNode | undefined; public right: LinkedListNode | undefined; public constructor(public readonly value: T) { this.right = undefined; this.left = undefined; } } type Node = LinkedListNode | undefined; export class DoublyLinkedList { public get head(): T | undefined { return this.headN === undefined ? undefined : this.headN.value; } public get isEmpty(): boolean { return this.length === 0; } public get tail(): T | undefined { return this.tailN === undefined ? undefined : this.tailN.value; } public length = 0; private headN: Node = undefined; private tailN: Node = undefined; public forEach(f: (_: T) => void) { let current = this.headN; while (current !== undefined) { f(current.value); current = current.right; } } public add(val: T): LinkedListNode { const node = new LinkedListNode(val); if (this.length === 0) { this.headN = node; } if (this.tailN === undefined) { this.tailN = node; } else { this.tailN.right = node; node.left = this.tailN; this.tailN = node; } this.length += 1; return node; } public empty(): void { this.length = 0; this.headN = this.tailN = undefined; } public pop(): T | undefined { const h = this.tailN; if (h !== undefined) { this.remove(h); return h.value; } return undefined; } public remove(n: LinkedListNode): void { if (n.removed) { return; } n.removed = true; if (n.left !== undefined && n.right !== undefined) { n.left.right = n.right; n.right.left = n.left; } else if (n.left !== undefined) { this.tailN = n.left; n.left.right = undefined; } else if (n.right !== undefined) { this.headN = n.right; n.right.left = undefined; } else { this.tailN = undefined; this.headN = undefined; } if (this.length > 0) { this.length -= 1; } } public shift(): T | undefined { const h = this.headN; if (h !== undefined) { this.remove(h); return h.value; } return undefined; } }