export class LinkedListNode { constructor( public value: T, public next: LinkedListNode | undefined = undefined, public previous: LinkedListNode | undefined = undefined ) {} } export default class LinkedList { // the element at the start of the list public head: LinkedListNode | undefined = undefined // the element at the end of the list public tail: LinkedListNode | undefined = undefined // the number of elements in the list public size: number = 0 constructor() {} /** * Iterates over the elements of the list */ public *[Symbol.iterator]() { let current = this.head while (current) { yield current current = current.next } } public forEach(callback: (value: LinkedListNode) => void) { let current = this.head while (current) { callback(current) current = current.next } } /** * Inserts an element at the end of the list * @param value */ public append(value: T) { const node = new LinkedListNode(value) if (!this.head) { this.head = node this.tail = node } else { this.tail!.next = node node.previous = this.tail this.tail = node } this.size++ } /** * Inserts an element at the start of the list * @param value */ public prepend(value: T) { const node = new LinkedListNode(value) if (!this.head) { this.head = node this.tail = node } else { this.head.previous = node node.next = this.head this.head = node } this.size++ } /** * Removes the first element from the list */ public dropFirst() { if (!this.head) { return } this.head = this.head.next if (this.head) { this.head.previous = undefined } else { this.tail = undefined } this.size-- } /** * Removes the last element from the list */ public dropLast() { if (!this.tail) { return } this.tail = this.tail.previous if (this.tail) { this.tail.next = undefined } else { this.head = undefined } this.size-- } /** * Inserts an element at a specific location in the list */ public insertAt(index: number, value: T) { if (index < 0 || index > this.size) { throw new Error('Index out of bounds') } if (index === 0) { this.prepend(value) return } if (index === this.size) { this.append(value) return } let current = this.head for (let i = 0; i < index - 1; i++) { current = current!.next } const node = new LinkedListNode(value) node.next = current!.next node.previous = current current!.next!.previous = node current!.next = node this.size++ } public find(value: T) { let current = this.head while (current) { if (current.value === value) { return current } current = current.next } return null } public toArray() { const array: T[] = [] let current = this.head while (current) { array.push(current.value) current = current.next } return array } public static fromArray(array: T[]) { const list = new LinkedList() for (const element of array) { list.append(element) } return list } }