75 lines
1.9 KiB
TypeScript
Raw Normal View History

2016-05-20 13:56:52 -07:00
export class Tree<T> {
/** @internal */
_root: TreeNode<T>;
constructor(root: TreeNode<T>) { this._root = root; }
get root(): T { return this._root.value; }
parent(t: T): T {
2016-05-20 13:56:52 -07:00
const p = this.pathFromRoot(t);
return p.length > 1 ? p[p.length - 2] : null;
}
children(t: T): T[] {
const n = findNode(t, this._root);
2016-05-21 17:35:55 -07:00
return n ? n.children.map(t => t.value) : [];
2016-05-20 13:56:52 -07:00
}
firstChild(t: T): T {
const n = findNode(t, this._root);
2016-05-20 13:56:52 -07:00
return n && n.children.length > 0 ? n.children[0].value : null;
}
2016-05-24 13:46:50 -07:00
siblings(t: T): T[] {
const p = findPath(t, this._root, []);
if (p.length < 2) return [];
const c = p[p.length - 2].children.map(c => c.value);
return c.filter(cc => cc !== t);
}
pathFromRoot(t: T): T[] { return findPath(t, this._root, []).map(s => s.value); }
2016-05-20 13:56:52 -07:00
contains(tree: Tree<T>): boolean { return contains(this._root, tree._root); }
2016-05-20 13:56:52 -07:00
}
function findNode<T>(expected: T, c: TreeNode<T>): TreeNode<T> {
2016-05-20 13:56:52 -07:00
if (expected === c.value) return c;
for (let cc of c.children) {
const r = findNode(expected, cc);
2016-05-20 13:56:52 -07:00
if (r) return r;
}
return null;
}
function findPath<T>(expected: T, c: TreeNode<T>, collected: TreeNode<T>[]): TreeNode<T>[] {
2016-05-20 13:56:52 -07:00
collected.push(c);
if (expected === c.value) return collected;
for (let cc of c.children) {
const cloned = collected.slice(0);
const r = findPath(expected, cc, cloned);
2016-05-20 13:56:52 -07:00
if (r) return r;
}
2016-05-21 17:35:55 -07:00
return [];
2016-05-20 13:56:52 -07:00
}
function contains<T>(tree: TreeNode<T>, subtree: TreeNode<T>): boolean {
2016-05-20 13:56:52 -07:00
if (tree.value !== subtree.value) return false;
for (let subtreeNode of subtree.children) {
const s = tree.children.filter(child => child.value === subtreeNode.value);
if (s.length === 0) return false;
if (!contains(s[0], subtreeNode)) return false;
2016-05-20 13:56:52 -07:00
}
return true;
}
export class TreeNode<T> {
constructor(public value: T, public children: TreeNode<T>[]) {}
2016-06-09 14:33:09 -07:00
toString(): string { return `TreeNode(${this.value})`; }
2016-05-20 13:56:52 -07:00
}