class TreeNode { val: number; left: TreeNode | null = null; right: TreeNode | null = null; constructor(val: number) { this.val = val; } } function insert(root: TreeNode | null, val: number): TreeNode { if (!root) return new TreeNode(val); if (val < root.val) root.left = insert(root.left, val); else root.right = insert(root.right, val); return root; } function preorder(root: TreeNode | null): string { if (!root) return ''; return root.val + ' ' + preorder(root.left) + preorder(root.right); } let root: TreeNode | null = null; [10, 5, 15, 3, 7, 12, 18].forEach(v => { root = insert(root, v); }); console.log(preorder(root).trim());
Think about how binary search tree insertion works and how preorder traversal visits nodes.
The insertion builds a binary search tree. Preorder traversal visits root, then left subtree, then right subtree. So the output is the root value first, then recursively the left subtree values, then right subtree values.
Think about how data is connected in a family tree or file system.
Trees naturally represent hierarchical relationships with nodes having multiple children. Arrays and linked lists are linear and cannot represent branching structures easily.
class Node { val: number; left: Node | null = null; right: Node | null = null; constructor(val: number) { this.val = val; } } function inorder(root: Node | null): number[] { let result: number[] = []; if (root === null) return result; inorder(root.left); inorder(root.right); return result; } const root = new Node(1); root.left = new Node(2); root.right = new Node(3); console.log(inorder(root));
Check how the recursive calls handle the result array.
The recursive calls to inorder do not accumulate results because the result array is local to each call and the recursive calls' results are ignored. So the returned array is empty.
Think about how to represent multiple children per node efficiently.
A tree with nodes having lists of children naturally models multiple subordinates per employee and allows traversal to find all subordinates efficiently.
class TreeNode { val: number; children: TreeNode[] = []; constructor(val: number) { this.val = val; } } function levelOrder(root: TreeNode | null): number[] { if (!root) return []; const queue: TreeNode[] = [root]; const result: number[] = []; while (queue.length > 0) { const node = queue.shift()!; result.push(node.val); for (const child of node.children) { queue.push(child); } } return result; } const root = new TreeNode(1); const child1 = new TreeNode(2); const child2 = new TreeNode(3); const child3 = new TreeNode(4); root.children.push(child1, child2); child1.children.push(child3); console.log(levelOrder(root));
Level order traversal visits nodes level by level from left to right.
The root is 1, its children 2 and 3 are next, then 2's child 4 is last. So the order is [1, 2, 3, 4].