class LinkedList { constructor() { this.head = null; this.tail = null; this.listSize = 0; } get size() { return this.listSize; } isLinked(node) { return !((node && node.prev === null && node.next === null && this.tail !== node && this.head !== node) || this.isEmpty()); } isEmpty() { return this.listSize === 0; } get first() { return this.head; } get last() { return this.last; } toString() { return this.toArray().toString(); } toArray() { var node = this.head, result = []; while (node !== null) { result.push(node); node = node.next; } return result; } // Note that modifying the list during // iteration is not safe. forEach(fun) { var node = this.head; while (node !== null) { fun(node); node = node.next; } } contains(n) { var node = this.head; if (!this.isLinked(n)) { return false; } while (node !== null) { if (node === n) { return true; } node = node.next; } return false; } at(i) { var node = this.head, index = 0; if (i >= this.listLength || i < 0) { return null; } while (node !== null) { if (i === index) { return node; } node = node.next; index += 1; } return null; } insertAfter(node, newNode) { if (!this.isLinked(node)) { return this; } newNode.prev = node; newNode.next = node.next; if (node.next === null) { this.tail = newNode; } else { node.next.prev = newNode; } node.next = newNode; this.listSize += 1; return this; } insertBefore(node, newNode) { if (!this.isLinked(node)) { return this; } newNode.prev = node.prev; newNode.next = node; if (node.prev === null) { this.head = newNode; } else { node.prev.next = newNode; } node.prev = newNode; this.listSize += 1; return this; } push(node) { if (this.head === null) { this.unshift(node); } else { this.insertAfter(this.tail, node); } return this; } unshift(node) { if (this.head === null) { this.head = node; this.tail = node; node.prev = null; node.next = null; this.listSize += 1; } else { this.insertBefore(this.head, node); } return this; } remove(node) { if (!this.isLinked(node)) { return this; } if (node.prev === null) { this.head = node.next; } else { node.prev.next = node.next; } if (node.next === null) { this.tail = node.prev; } else { node.next.prev = node.prev; } this.listSize -= 1; return this; } pop() { var node = this.tail; this.tail.prev.next = null; this.tail = this.tail.prev; this.listSize -= 1; node.prev = null; node.next = null; return node; } shift() { var node = this.head; this.head.next.prev = null; this.head = this.head.next; this.listSize -= 1; node.prev = null; node.next = null; return node; } } class Node { constructor(data) { this.prev = null; this.next = null; this.data = data; } toString() { return this.data.toString(); } }