Tree
A hierarchical data structure consisting of nodes where each node can have multiple children. Unlike binary trees, nodes are not limited to two children.
Overview
General trees represent hierarchical relationships where each node can have any number of children. This structure is fundamental for representing file systems, organizational charts, and nested data.
Implementation
Node Structure
class Node < T = number > {
value : T ;
children : Node < T >[] = [];
constructor ( value : T ) {
this . value = value ;
}
}
Reference : node.ts:1-9
Class Definition
class Tree < T > {
root : Node < T > | null = null ;
constructor ( root : T ) {
this . root = new Node ( root );
}
// ... methods
}
Reference : tree.ts:3-8
API Reference
insert(parent: T, node: T): boolean
Inserts a new node as a child of the specified parent node.
const tree = new Tree < number >( 1 );
tree . insert ( 1 , 2 ); // Add 2 as child of 1
tree . insert ( 1 , 3 ); // Add 3 as child of 1
tree . insert ( 2 , 4 ); // Add 4 as child of 2
// Tree structure:
// 1
// / \
// 2 3
// /
// 4
Parameters :
parent: Value of the parent node
node: Value to insert as a new child
Returns : true if insertion succeeded, false if parent not found
Complexity : O(n) - must search for parent node
Reference : tree.ts:23-38
search(value: T): Node<T> | undefined
Searches for a node with the specified value.
const tree = new Tree < number >( 1 );
tree . insert ( 1 , 2 );
tree . insert ( 1 , 3 );
const node = tree . search ( 2 );
console . log ( node ?. value ); // 2
console . log ( node ?. children ); // []
Parameters :
value: The value to search for
Returns : The node if found, undefined otherwise
Complexity : O(n) - may need to traverse entire tree
Reference : tree.ts:40-50
Internal Methods
#traverse(node, callback)
Private method for tree traversal using depth-first search.
# traverse ( node : Node < T > | null , callback : ( node : Node < T >) => void ) {
if ( ! node ) {
return ;
}
callback ( node );
for ( const child of node . children ) {
callback ( child );
this . #traverse ( child , callback );
}
}
Traversal Order : Pre-order (parent, then children)
Reference : tree.ts:10-21
Usage Examples
Building a File System
class FileSystem {
private tree : Tree < string >;
constructor ( rootDir : string ) {
this . tree = new Tree ( rootDir );
}
createDirectory ( parent : string , dirName : string ) {
return this . tree . insert ( parent , dirName );
}
findDirectory ( dirName : string ) {
return this . tree . search ( dirName );
}
}
const fs = new FileSystem ( '/' );
fs . createDirectory ( '/' , 'home' );
fs . createDirectory ( '/' , 'etc' );
fs . createDirectory ( '/home' , 'user' );
fs . createDirectory ( '/home/user' , 'documents' );
// File system structure:
// /
// / \
// home etc
// |
// user
// |
// documents
Organization Chart
interface Employee {
id : number ;
name : string ;
role : string ;
}
const orgChart = new Tree < Employee >({
id: 1 ,
name: 'CEO' ,
role: 'Chief Executive'
});
orgChart . insert (
{ id: 1 , name: 'CEO' , role: 'Chief Executive' },
{ id: 2 , name: 'CTO' , role: 'Technology' }
);
orgChart . insert (
{ id: 1 , name: 'CEO' , role: 'Chief Executive' },
{ id: 3 , name: 'CFO' , role: 'Finance' }
);
interface MenuItem {
id : string ;
label : string ;
url ?: string ;
}
const menu = new Tree < MenuItem >({
id: 'root' ,
label: 'Main Menu'
});
menu . insert (
{ id: 'root' , label: 'Main Menu' },
{ id: 'products' , label: 'Products' }
);
menu . insert (
{ id: 'products' , label: 'Products' },
{ id: 'laptops' , label: 'Laptops' , url: '/products/laptops' }
);
menu . insert (
{ id: 'products' , label: 'Products' },
{ id: 'phones' , label: 'Phones' , url: '/products/phones' }
);
Traversal Patterns
Depth-First Search (DFS)
The implementation uses DFS for traversal:
function printTree < T >( tree : Tree < T >) {
const values : T [] = [];
tree . #traverse ( tree . root , ( node ) => {
values . push ( node . value );
});
console . log ( values );
}
Custom Traversal
// Count total nodes
function countNodes < T >( tree : Tree < T >) : number {
let count = 0 ;
tree . #traverse ( tree . root , () => {
count ++ ;
});
return count ;
}
// Find maximum depth
function maxDepth < T >( node : Node < T > | null ) : number {
if ( ! node || node . children . length === 0 ) {
return 0 ;
}
let max = 0 ;
for ( const child of node . children ) {
max = Math . max ( max , maxDepth ( child ));
}
return max + 1 ;
}
Complexity Summary
Operation Time Complexity Space Complexity insert O(n) O(1) search O(n) O(h)* traverse O(n) O(h)*
*h = height of tree (due to recursion call stack)
Tree vs Other Structures
Feature General Tree Binary Tree N-ary Tree Children per node Unlimited Max 2 Max N Storage Dynamic array Two pointers Fixed array Use case Hierarchies Search trees Tries, B-trees Memory Variable Fixed Fixed
Key Characteristics
Advantages:
Natural representation of hierarchies
Flexible number of children
Intuitive for nested data
Easy to implement recursive algorithms
Limitations:
No guaranteed balance
O(n) search time
Not optimized for searching
Memory overhead for children array
Common Operations
Finding Leaf Nodes
function findLeaves < T >( tree : Tree < T >) : Node < T >[] {
const leaves : Node < T >[] = [];
function traverse ( node : Node < T > | null ) {
if ( ! node ) return ;
if ( node . children . length === 0 ) {
leaves . push ( node );
}
for ( const child of node . children ) {
traverse ( child );
}
}
traverse ( tree . root );
return leaves ;
}
Finding Height
function height < T >( node : Node < T > | null ) : number {
if ( ! node ) return - 1 ;
let maxChildHeight = - 1 ;
for ( const child of node . children ) {
maxChildHeight = Math . max ( maxChildHeight , height ( child ));
}
return maxChildHeight + 1 ;
}
Level-Order Traversal
function levelOrder < T >( tree : Tree < T >) : T [][] {
if ( ! tree . root ) return [];
const result : T [][] = [];
const queue : Node < T >[] = [ tree . root ];
while ( queue . length > 0 ) {
const levelSize = queue . length ;
const currentLevel : T [] = [];
for ( let i = 0 ; i < levelSize ; i ++ ) {
const node = queue . shift () ! ;
currentLevel . push ( node . value );
queue . push ( ... node . children );
}
result . push ( currentLevel );
}
return result ;
}
When to Use a General Tree
Directories can contain multiple files and subdirectories.
HTML elements can have any number of child elements.
Employees can manage multiple direct reports.
Code expressions can have varying numbers of operands.
For optimized searching, consider using specialized tree structures:
Binary Search Tree Optimized tree for searching
Graph Generalization allowing cycles