typescript-dsa
Version:
Collection of common data structures / algorithms implemented in TypeScript
142 lines (122 loc) • 5.04 kB
text/typescript
enum TreeErrors {
NO_TREE_GIVEN="If not removing by node value, must provide a Tree as to_remove argument"
}
/**
* A tree.
*/
export class Tree<T> {
/**
* The value of the root of this tree.
*/
value: T;
/**
* The children of this tree.
*/
#children: Tree<T>[] = [];
get children(): Tree<T>[] {
return this.#children;
}
/**
* - You can specify a list of Trees or raw values or a mix of both.
* - Raw values will be converted to leaf nodes.
*/
set children(new_children: (Tree<T> | T)[]) {
this.#children = new_children.map(child => {
if(child instanceof Tree) return child;
return new Tree<T>(child);
});
}
/**
* Removes one or more child nodes. Does not recurse.
* @param to_remove The value or node to remove.
*
* - Specify a `Tree` when wanting to remove a specific node.
*
* - Specify a value of the generic type to remove any first-level children with the given value.
* @param by_value Whether to remove children by value or by strict comparison between Tree objects.
* `to_remove` must be a Tree if false. When `to_remove` is a Tree and this is `true`, removes first-level children based on the value of the given node.
* @returns The new list of children.
*/
remove(to_remove: Tree<T> | T, by_value: boolean=false): Tree<T>[] {
if(by_value) {
if(to_remove instanceof Tree) {
this.children = this.children.filter(x => x.value !== to_remove.value);
} else {
this.children = this.children.filter(x => x.value !== to_remove);
}
} else {
if(!(to_remove instanceof Tree)) {
throw Error(TreeErrors.NO_TREE_GIVEN);
}
this.children = this.children.filter(x => x !== to_remove);
}
return this.children;
}
/**
* Performs a depth-first filter on the tree generated by the node.
* @param filter The filter function to use.
* @returns An array of Trees that match the filter function provided in DFS order.
*/
depth_first_filter(filter: (_: Tree<T>) => boolean): Tree<T>[] {
let result: Tree<T>[] = [];
if(filter(this)) result.push(this);
this.#children.forEach(child => {
result = [...result, ...child.depth_first_filter(filter)];
});
return result;
}
/**
* Performs a breadth-first filter on the tree generated by the node.
* @param filter The filter function to use.
* @returns An array of Trees that match the filter function provided in BFS order.
* @todo The implementation is probably suboptimal.
*/
breadth_first_filter(filter: (_: Tree<T>) => boolean): Tree<T>[] {
let result: Tree<T>[] = [];
if(filter(this)) result.push(this);
this.children.forEach(child => {
if(filter(child)) result.push(child);
});
this.children.forEach(child => {
let child_res = child.breadth_first_filter(filter);
if(filter(this)) child_res = child_res.slice(1);
result = [...result, ...child_res];
});
return result;
}
/**
* Performs a {@link https://en.wikipedia.org/wiki/Depth-first_search depth-first search} for the given value.
* @param value The value to compare against.
* @param strict Whether to do strict (===) or loose (==) comparsion. Defaults to `true` (strict).
* @returns An array of tree nodes with the given `value`, appearing in order they were found in the depth-first search.
*/
depth_first_search(value: T, strict: boolean=true): Tree<T>[] {
if(strict) {
return this.depth_first_filter(node => value === node.value);
} else {
return this.depth_first_filter(node => value == node.value);
}
}
/**
* Performs a {@link https://en.wikipedia.org/wiki/Breadth-first_search breadth-first search} for the given value.
* @param value The value to compare against.
* @param strict Whether to do strict (===) or loose (==) comparsion. Defaults to `true` (strict).
* @returns An array of tree nodes with the given `value`, appearing in order they were found in the breadth-first search.
*/
breadth_first_search(value: T, strict: boolean=true): Tree<T>[] {
if(strict) {
return this.depth_first_filter(node => value === node.value);
} else {
return this.depth_first_filter(node => value == node.value);
}
}
/**
* @param initial_value Satellite data of the node.
* @param children An array of children of the node.
* `children` can be an array of nodes or raw values or both. Raw values will be converted to leaves.
*/
constructor(initial_value: T, children: (Tree<T> | T)[]=[]) {
this.value = initial_value;
this.children = children;
}
};