class Tree { value: T; children: Tree[] = []; constructor(value?: T, children?: Tree[]) { this.value = value || ({} as T); this.children = children || []; } addChild(child: T) { this.children.push(new Tree(child)); } removeChild(child: T) { this.children = this.children.filter((node) => node.value !== child); } findNode(value: T, callBack?: (val: Tree) => void): Tree | undefined { // find node by dfs in children for (const child of this.children) { if (child.value === value) { if (callBack) { callBack(child); } return child; } else { const node = child.findNode(value, callBack); if (node) return node; } } return undefined; } removeNode(value: T) { // find node by dfs in children and remove it this.children = this.children.filter((child) => { if (child.value === value) return false; child.removeNode(value); return true; }); } findIndex(value: T, filter: (value: Tree, index: number, array: Tree[]) => boolean): number { // nth children index let index = 0; for (const child of this.children.filter(filter)) { if (child.value === value) { return index; } else { let cindex = 0; if (child.children.length > 0) { cindex = child.findIndex(value, filter); } index += cindex + 1; } } return -1; } traverseBFS(fn: (node: Tree) => void) { const arr: Tree[] = [this]; while (arr.length) { const node = arr.shift(); if (!node) continue; arr.push(...node.children); fn(node); } } traverseDFS(fn: (node: Tree) => void) { const arr: Tree[] = [this]; while (arr.length) { const node = arr.shift(); if (!node) continue; arr.unshift(...node.children); fn(node); } } } export { Tree };