import type { AlgorithmDefinition } from '@/lib/visualizations/types'; /** * Tree structure (level order: [4, 2, 6, 1, 3, 5, 7]): * * 4 (root) * / \ * 2 6 * / \ / \ * 1 3 5 7 * * DFS (Preorder) output: [4, 2, 1, 3, 6, 5, 7] */ // Node IDs for our tree const NODE_4 = 'n4'; const NODE_2 = 'n2'; const NODE_6 = 'n6'; const NODE_1 = 'n1'; const NODE_3 = 'n3'; const NODE_5 = 'n5'; const NODE_7 = 'n7'; // Helper to create tree state with specific node states function createTreeState(nodeStates: Record) { return { id: 'tree', label: 'Binary Search Tree', rootId: NODE_4, nodes: [ { id: NODE_4, value: 4, state: nodeStates[NODE_4] ?? 'normal', left: NODE_2, right: NODE_6 }, { id: NODE_2, value: 2, state: nodeStates[NODE_2] ?? 'normal', left: NODE_1, right: NODE_3 }, { id: NODE_6, value: 6, state: nodeStates[NODE_6] ?? 'normal', left: NODE_5, right: NODE_7 }, { id: NODE_1, value: 1, state: nodeStates[NODE_1] ?? 'normal', left: null, right: null }, { id: NODE_3, value: 3, state: nodeStates[NODE_3] ?? 'normal', left: null, right: null }, { id: NODE_5, value: 5, state: nodeStates[NODE_5] ?? 'normal', left: null, right: null }, { id: NODE_7, value: 7, state: nodeStates[NODE_7] ?? 'normal', left: null, right: null }, ], }; } // Helper to create stack state function createStackState(values: number[], highlightTop = false) { return { id: 'dfs-stack', label: 'Stack', elements: values.map((v, i) => ({ id: `stack-${v}-${i}`, value: v, state: (highlightTop && i === values.length - 1 ? 'highlighted' : 'normal') as 'normal' | 'highlighted', })), }; } // Helper to create output array state function createOutputState(values: (number | null)[], highlightIndex?: number) { const maxLen = 7; const elements = []; for (let i = 0; i < maxLen; i++) { const val = values[i]; elements.push({ value: val ?? 0, index: i, state: (val === null ? 'dimmed' : i === highlightIndex ? 'highlighted' : 'success') as 'normal' | 'highlighted' | 'dimmed' | 'success' | 'comparing', }); } return { id: 'output', label: 'Output Array', elements, }; } export const dfsAlgorithm: AlgorithmDefinition = { id: 'dfs', title: 'Depth-First Search (DFS)', slug: 'dfs', pattern: { name: 'DFS', description: 'Use a stack to explore as deep as possible along each branch before backtracking.', }, problemStatement: 'Given a binary tree, traverse it depth-first (preorder: Root-Left-Right) and return the values in the order visited.', intuition: 'DFS explores one branch completely before backtracking. Using a stack (LIFO) naturally achieves this: we pop a node, process it, then push its children. By pushing right before left, we ensure left children are processed first.', code: { language: 'python', code: `def dfs(root): if not root: return [] result = [] stack = [root] while stack: # Pop top node node = stack.pop() result.append(node.val) # Push right first, then left (so left is popped first) if node.right: stack.append(node.right) if node.left: stack.append(node.left) return result`, }, initialExample: { input: { tree: [4, 2, 6, 1, 3, 5, 7] }, expected: [4, 2, 1, 3, 6, 5, 7], }, steps: [ // ========================================== // Phase 1: Problem (2 steps) // ========================================== { id: 'problem-1', phase: 'problem', explanation: 'We have a binary tree. Our goal is to visit all nodes depth-first: go as deep as possible down each branch before backtracking.', dataState: { arrays: [], pointers: [], variables: [], calculations: [], trees: [createTreeState({})], stacks: [createStackState([])], }, }, { id: 'problem-2', phase: 'problem', explanation: 'Preorder DFS visits Root, then Left subtree, then Right subtree. Expected output: [4, 2, 1, 3, 6, 5, 7].', dataState: { arrays: [createOutputState([null, null, null, null, null, null, null])], pointers: [], variables: [], calculations: [], trees: [createTreeState({ [NODE_4]: 'highlighted' })], stacks: [createStackState([])], }, }, // ========================================== // Phase 2: Intuition (3 steps) // ========================================== { id: 'intuition-1', phase: 'intuition', explanation: 'DFS uses a stack (LIFO). We start by pushing the root, then repeatedly: pop a node, process it, and push its children.', dataState: { arrays: [createOutputState([null, null, null, null, null, null, null])], pointers: [], variables: [], calculations: [], trees: [createTreeState({ [NODE_4]: 'current' })], stacks: [createStackState([4], true)], }, }, { id: 'intuition-2', phase: 'intuition', explanation: 'Key trick: Push right child BEFORE left child. Since stack is LIFO, left child will be popped (and processed) first!', dataState: { arrays: [createOutputState([4, null, null, null, null, null, null], 0)], pointers: [], variables: [], calculations: [], trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visiting', [NODE_6]: 'visiting' })], stacks: [createStackState([6, 2], true)], }, }, { id: 'intuition-3', phase: 'intuition', explanation: 'The stack remembers where to backtrack. When we finish the left subtree, the right subtree is waiting on the stack.', dataState: { arrays: [createOutputState([4, 2, null, null, null, null, null])], pointers: [], variables: [], calculations: [], trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_1]: 'visiting', [NODE_3]: 'visiting', [NODE_6]: 'visiting' })], stacks: [createStackState([6, 3, 1], true)], }, }, // ========================================== // Phase 3: Pattern (2 steps) // ========================================== { id: 'pattern-1', phase: 'pattern', explanation: 'DFS pattern: (1) Initialize stack with root, (2) While stack not empty: pop, process, push children (right then left).', dataState: { arrays: [createOutputState([null, null, null, null, null, null, null])], pointers: [], variables: [], calculations: [], trees: [createTreeState({})], stacks: [createStackState([])], }, }, { id: 'pattern-2', phase: 'pattern', explanation: 'The stack ensures depth-first order: we completely explore one subtree before moving to its sibling.', dataState: { arrays: [createOutputState([null, null, null, null, null, null, null])], pointers: [], variables: [ { id: 'stack', name: 'stack', value: 'LIFO' }, { id: 'result', name: 'result', value: '[]' }, ], calculations: [], trees: [createTreeState({ [NODE_4]: 'current' })], stacks: [createStackState([4], true)], }, }, // ========================================== // Phase 4: Code (3 steps) // ========================================== { id: 'code-1', phase: 'code', explanation: 'Initialize: empty result list, stack containing just the root node.', codeLine: 5, codeHighlightLines: [5, 6, 7], dataState: { arrays: [createOutputState([null, null, null, null, null, null, null])], pointers: [], variables: [ { id: 'result', name: 'result', value: '[]' }, ], calculations: [], trees: [createTreeState({ [NODE_4]: 'current' })], stacks: [createStackState([4], true)], }, }, { id: 'code-2', phase: 'code', explanation: 'Main loop: While stack is not empty, pop the top node and add its value to result.', codeLine: 10, codeHighlightLines: [9, 10, 11, 12], dataState: { arrays: [createOutputState([4, null, null, null, null, null, null], 0)], pointers: [], variables: [], calculations: [], trees: [createTreeState({ [NODE_4]: 'visited' })], stacks: [createStackState([])], }, }, { id: 'code-3', phase: 'code', explanation: 'Push right child first, then left child. LIFO means left will be popped first, ensuring we go left before right.', codeLine: 15, codeHighlightLines: [14, 15, 16, 17, 18], dataState: { arrays: [createOutputState([4, null, null, null, null, null, null])], pointers: [], variables: [], calculations: [], trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visiting', [NODE_6]: 'visiting' })], stacks: [createStackState([6, 2], true)], }, }, // ========================================== // Phase 5: Execution (10 steps) // ========================================== { id: 'exec-1', phase: 'execution', explanation: 'Start: stack = [4], result = []. Pop 4, add to result. Push right (6) then left (2).', codeLine: 12, dataState: { arrays: [createOutputState([4, null, null, null, null, null, null], 0)], pointers: [], variables: [ { id: 'node', name: 'node', value: 4 }, { id: 'result', name: 'result', value: '[4]' }, ], calculations: [], trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visiting', [NODE_6]: 'visiting' })], stacks: [createStackState([6, 2], true)], }, }, { id: 'exec-2', phase: 'execution', explanation: 'Stack: [6, 2]. Pop 2 (top). Result: [4, 2]. Push right (3) then left (1). Stack: [6, 3, 1].', codeLine: 12, dataState: { arrays: [createOutputState([4, 2, null, null, null, null, null], 1)], pointers: [], variables: [ { id: 'node', name: 'node', value: 2, previousValue: 4 }, { id: 'result', name: 'result', value: '[4, 2]' }, ], calculations: [], trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_1]: 'visiting', [NODE_3]: 'visiting', [NODE_6]: 'visiting' })], stacks: [createStackState([6, 3, 1], true)], }, }, { id: 'exec-3', phase: 'execution', explanation: 'Stack: [6, 3, 1]. Pop 1 (top). Result: [4, 2, 1]. Node 1 has no children. Stack: [6, 3].', codeLine: 12, dataState: { arrays: [createOutputState([4, 2, 1, null, null, null, null], 2)], pointers: [], variables: [ { id: 'node', name: 'node', value: 1, previousValue: 2 }, { id: 'result', name: 'result', value: '[4, 2, 1]' }, ], calculations: [], trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visiting', [NODE_6]: 'visiting' })], stacks: [createStackState([6, 3], true)], }, }, { id: 'exec-4', phase: 'execution', explanation: 'Stack: [6, 3]. Pop 3 (top). Result: [4, 2, 1, 3]. Node 3 has no children. Stack: [6]. Left subtree done!', codeLine: 12, dataState: { arrays: [createOutputState([4, 2, 1, 3, null, null, null], 3)], pointers: [], variables: [ { id: 'node', name: 'node', value: 3, previousValue: 1 }, { id: 'result', name: 'result', value: '[4, 2, 1, 3]' }, ], calculations: [], trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_6]: 'visiting' })], stacks: [createStackState([6], true)], }, }, { id: 'exec-5', phase: 'execution', explanation: 'Stack: [6]. Pop 6 (top). Result: [4, 2, 1, 3, 6]. Push right (7) then left (5). Now exploring right subtree!', codeLine: 12, dataState: { arrays: [createOutputState([4, 2, 1, 3, 6, null, null], 4)], pointers: [], variables: [ { id: 'node', name: 'node', value: 6, previousValue: 3 }, { id: 'result', name: 'result', value: '[4, 2, 1, 3, 6]' }, ], calculations: [], trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_6]: 'visited', [NODE_5]: 'visiting', [NODE_7]: 'visiting' })], stacks: [createStackState([7, 5], true)], }, }, { id: 'exec-6', phase: 'execution', explanation: 'Stack: [7, 5]. Pop 5 (top). Result: [4, 2, 1, 3, 6, 5]. Node 5 has no children. Stack: [7].', codeLine: 12, dataState: { arrays: [createOutputState([4, 2, 1, 3, 6, 5, null], 5)], pointers: [], variables: [ { id: 'node', name: 'node', value: 5, previousValue: 6 }, { id: 'result', name: 'result', value: '[4, 2, 1, 3, 6, 5]' }, ], calculations: [], trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_6]: 'visited', [NODE_5]: 'visited', [NODE_7]: 'visiting' })], stacks: [createStackState([7], true)], }, }, { id: 'exec-7', phase: 'execution', explanation: 'Stack: [7]. Pop 7 (top). Result: [4, 2, 1, 3, 6, 5, 7]. Node 7 has no children. Stack: [].', codeLine: 12, dataState: { arrays: [createOutputState([4, 2, 1, 3, 6, 5, 7], 6)], pointers: [], variables: [ { id: 'node', name: 'node', value: 7, previousValue: 5 }, { id: 'result', name: 'result', value: '[4, 2, 1, 3, 6, 5, 7]' }, ], calculations: [], trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_6]: 'visited', [NODE_5]: 'visited', [NODE_7]: 'visited' })], stacks: [createStackState([])], }, }, { id: 'exec-8', phase: 'execution', explanation: 'Stack is empty! All nodes have been visited. Final result: [4, 2, 1, 3, 6, 5, 7] - preorder DFS traversal.', codeLine: 20, dataState: { arrays: [createOutputState([4, 2, 1, 3, 6, 5, 7])], pointers: [], variables: [ { id: 'result', name: 'result', value: '[4, 2, 1, 3, 6, 5, 7]' }, ], calculations: [], trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_6]: 'visited', [NODE_5]: 'visited', [NODE_7]: 'visited' })], stacks: [createStackState([])], }, }, ], };