export class TwoWayLinkedList { private count = 0; private entryNode: Node = null; private lastNode: Node = null; private nodePtr: Node = null; public push(newNode: T): TwoWayLinkedList { if (null === this.lastNode) { this.entryNode = new Node(newNode); this.lastNode = this.entryNode; this.nodePtr = this.entryNode; this.entryNode .setPrev(this.entryNode) .setNext(this.entryNode); } else { const prevPtr = this.lastNode; const nodeToAdd = new Node(newNode); nodeToAdd.setNext(this.entryNode).setPrev(prevPtr); prevPtr.setNext(nodeToAdd); this.lastNode = nodeToAdd; } this.count++; return this; } public pop(): T { if (null === this.lastNode) { throw new Error('No items in list'); } let returnData: T; if (this.entryNode === this.lastNode) { returnData = this.lastNode.getData(); this.lastNode.setPrev(null).setNext(null); this.entryNode = null; this.lastNode = null; this.nodePtr = null; } else { const newLast = this.lastNode.getPrev(); if (this.nodePtr === this.lastNode) { this.nodePtr = newLast; } newLast.setNext(this.entryNode); returnData = this.lastNode.getData(); this.lastNode.setPrev(null).setNext(null); this.lastNode = newLast; } this.count--; return returnData; } public clear() { while (this.count > 0) { this.pop(); } } public prev(): T { this.nodePtr = this.nodePtr.getPrev(); return this.nodePtr.getData(); } public next(): T { this.nodePtr = this.nodePtr.getNext(); return this.nodePtr.getData(); } public isFirst(): boolean { return this.nodePtr === this.lastNode; } public isLast(): boolean { return this.nodePtr === this.lastNode; } public get first(): T { return this.entryNode.getData(); } public get last(): T { return this.lastNode.getData(); } } export class Node { private prev: Node = null; private next: Node = null; private readonly data: T = null; constructor(data: T) { this.data = data; } public getPrev(): Node { return this.prev; } public setPrev(node: Node): Node { this.prev = node; return this; } public getNext(): Node { return this.next; } public setNext(node: Node): Node { this.next = node; return this; } public getData(): T { return this.data; } }