+): number {
+ if (!nodeId) return 0;
+ const node = nodeMap.get(nodeId);
+ if (!node) return 0;
+ const leftDepth = calculateTreeDepth(node.left, nodeMap);
+ const rightDepth = calculateTreeDepth(node.right, nodeMap);
+ return 1 + Math.max(leftDepth, rightDepth);
+}
+
+function calculatePositions(
+ tree: BinaryTreeState,
+ totalWidth: number
+): NodePosition[] {
+ const nodeMap = buildNodeMap(tree.nodes);
+ const positions: NodePosition[] = [];
+
+ function traverse(
+ nodeId: string | null,
+ level: number,
+ left: number,
+ right: number,
+ parentX?: number,
+ parentY?: number
+ ) {
+ if (!nodeId) return;
+ const node = nodeMap.get(nodeId);
+ if (!node) return;
+
+ const x = (left + right) / 2;
+ const y = SVG_PADDING + level * LEVEL_HEIGHT + NODE_RADIUS;
+
+ positions.push({ node, x, y, parentX, parentY });
+
+ const childWidth = (right - left) / 2;
+ traverse(node.left, level + 1, left, left + childWidth, x, y);
+ traverse(node.right, level + 1, left + childWidth, right, x, y);
+ }
+
+ traverse(tree.rootId, 0, 0, totalWidth);
+ return positions;
+}
+
+export function BinaryTreeView({
+ tree,
+ currentNodeId,
+ className,
+}: BinaryTreeViewProps) {
+ const { positions, svgWidth, svgHeight } = useMemo(() => {
+ const nodeMap = buildNodeMap(tree.nodes);
+ const depth = calculateTreeDepth(tree.rootId, nodeMap);
+ const maxNodesAtBottom = Math.pow(2, depth - 1);
+ const width = Math.max(
+ maxNodesAtBottom * MIN_NODE_SPACING + SVG_PADDING * 2,
+ 200
+ );
+ const height = depth * LEVEL_HEIGHT + SVG_PADDING * 2;
+ const pos = calculatePositions(tree, width);
+ return { positions: pos, svgWidth: width, svgHeight: height };
+ }, [tree]);
+
+ return (
+
+ {tree.label && (
+
+ {tree.label}
+
+ )}
+
+
+ );
+}
diff --git a/frontend/src/components/visualizations-new/data-structures/queue-view.tsx b/frontend/src/components/visualizations-new/data-structures/queue-view.tsx
new file mode 100644
index 0000000..ae475b3
--- /dev/null
+++ b/frontend/src/components/visualizations-new/data-structures/queue-view.tsx
@@ -0,0 +1,55 @@
+'use client';
+
+import { AnimatePresence } from 'framer-motion';
+import { cn } from '@/lib/utils';
+import type { QueueState } from '@/lib/visualizations/types';
+import { QueueElement } from '../primitives/queue-element';
+
+interface QueueViewProps {
+ queue: QueueState;
+ className?: string;
+}
+
+export function QueueView({ queue, className }: QueueViewProps) {
+ const hasElements = queue.elements.length > 0;
+
+ return (
+
+ {queue.label && (
+
+ {queue.label}
+
+ )}
+
+
+ {/* Empty state */}
+ {!hasElements && (
+
+ empty
+
+ )}
+
+ {/* Queue elements - horizontal row, front on left, rear on right */}
+
+ {queue.elements.map((element, index) => (
+ 1}
+ />
+ ))}
+
+
+
+ {/* Direction indicator */}
+
+ dequeue
+ ←
+
+ →
+ enqueue
+
+
+ );
+}
diff --git a/frontend/src/components/visualizations-new/index.ts b/frontend/src/components/visualizations-new/index.ts
index 6a89d41..9e7e61e 100644
--- a/frontend/src/components/visualizations-new/index.ts
+++ b/frontend/src/components/visualizations-new/index.ts
@@ -12,14 +12,21 @@ export { CalculationBubble } from "./primitives/calculation-bubble";
export { LinkedListNode } from "./primitives/linked-list-node";
export { LinkedListPointer } from "./primitives/linked-list-pointer";
export { StackElement } from "./primitives/stack-element";
+export { QueueElement } from "./primitives/queue-element";
+export { TreeNode } from "./primitives/tree-node";
// Data structures
export { ArrayView } from "./data-structures/array-view";
export { LinkedListView } from "./data-structures/linked-list-view";
export { StackView } from "./data-structures/stack-view";
+export { QueueView } from "./data-structures/queue-view";
+export { BinaryTreeView } from "./data-structures/binary-tree-view";
// Algorithm visualizations
export { MonotonicStackVisualization } from "./algorithms/monotonic-stack";
export { PrefixSumVisualization } from "./algorithms/prefix-sum";
+export { TreeTraversalVisualization } from "./algorithms/tree-traversal";
+export { BFSVisualization } from "./algorithms/bfs";
+export { DFSVisualization } from "./algorithms/dfs";
export { TwoPointersVisualization } from "./algorithms/two-pointers";
export { LinkedListVisualization } from "./algorithms/linked-list";
diff --git a/frontend/src/components/visualizations-new/primitives/queue-element.tsx b/frontend/src/components/visualizations-new/primitives/queue-element.tsx
new file mode 100644
index 0000000..721e281
--- /dev/null
+++ b/frontend/src/components/visualizations-new/primitives/queue-element.tsx
@@ -0,0 +1,61 @@
+'use client';
+
+import { motion } from 'framer-motion';
+import { cn } from '@/lib/utils';
+import type { QueueElementState } from '@/lib/visualizations/types';
+
+interface QueueElementProps {
+ element: QueueElementState;
+ isFront?: boolean;
+ isRear?: boolean;
+ className?: string;
+}
+
+const STATE_CLASSES = {
+ normal: 'bg-[var(--surface-variant)] border-[var(--border)] text-[var(--foreground)]',
+ highlighted: 'bg-[var(--primary)]/20 border-[var(--primary)] text-[var(--primary)]',
+ enqueued: 'bg-[var(--success)]/20 border-[var(--success)] text-[var(--success)]',
+ dequeued: 'bg-[var(--error)]/20 border-[var(--error)] text-[var(--error)]',
+} as const;
+
+export function QueueElement({
+ element,
+ isFront = false,
+ isRear = false,
+ className,
+}: QueueElementProps) {
+ return (
+
+ {element.value}
+ {isFront && (
+
+ FRONT
+
+ )}
+ {isRear && (
+
+ REAR
+
+ )}
+
+ );
+}
diff --git a/frontend/src/components/visualizations-new/primitives/tree-node.tsx b/frontend/src/components/visualizations-new/primitives/tree-node.tsx
new file mode 100644
index 0000000..41bc15a
--- /dev/null
+++ b/frontend/src/components/visualizations-new/primitives/tree-node.tsx
@@ -0,0 +1,83 @@
+'use client';
+
+import { motion } from 'framer-motion';
+import { cn } from '@/lib/utils';
+import type { BinaryTreeNodeState } from '@/lib/visualizations/types';
+
+interface TreeNodeProps {
+ node: BinaryTreeNodeState;
+ x: number;
+ y: number;
+ radius?: number;
+ className?: string;
+}
+
+const STATE_CLASSES = {
+ normal: 'fill-[var(--surface-variant)] stroke-[var(--border)]',
+ current: 'fill-[var(--primary)]/20 stroke-[var(--primary)]',
+ visiting: 'fill-[var(--info)]/20 stroke-[var(--info)]',
+ visited: 'fill-[var(--success)]/20 stroke-[var(--success)] opacity-70',
+ highlighted: 'fill-[var(--primary)]/30 stroke-[var(--primary)]',
+} as const;
+
+const TEXT_CLASSES = {
+ normal: 'fill-[var(--foreground)]',
+ current: 'fill-[var(--primary)]',
+ visiting: 'fill-[var(--info)]',
+ visited: 'fill-[var(--success)]',
+ highlighted: 'fill-[var(--primary)]',
+} as const;
+
+export function TreeNode({
+ node,
+ x,
+ y,
+ radius = 24,
+ className,
+}: TreeNodeProps) {
+ const isActive = node.state === 'current' || node.state === 'highlighted';
+
+ return (
+
+
+
+ {node.value}
+
+
+ );
+}
diff --git a/frontend/src/content/algorithms/bfs.ts b/frontend/src/content/algorithms/bfs.ts
new file mode 100644
index 0000000..9af4de6
--- /dev/null
+++ b/frontend/src/content/algorithms/bfs.ts
@@ -0,0 +1,445 @@
+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
+ *
+ * BFS (Level-order) output: [4, 2, 6, 1, 3, 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 queue state
+function createQueueState(values: number[], highlightFront = false, newRear = false) {
+ return {
+ id: 'bfs-queue',
+ label: 'Queue',
+ elements: values.map((v, i) => ({
+ id: `queue-${v}-${i}`,
+ value: v,
+ state: (highlightFront && i === 0 ? 'highlighted' : newRear && i === values.length - 1 ? 'enqueued' : 'normal') as 'normal' | 'highlighted' | 'enqueued' | 'dequeued',
+ })),
+ };
+}
+
+// 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 bfsAlgorithm: AlgorithmDefinition = {
+ id: 'bfs',
+ title: 'Breadth-First Search (BFS)',
+ slug: 'bfs',
+ pattern: {
+ name: 'BFS',
+ description:
+ 'Use a queue to explore nodes level by level, visiting all nodes at the current depth before moving deeper.',
+ },
+ problemStatement:
+ 'Given a binary tree, traverse it level by level (breadth-first) and return the values in the order visited.',
+ intuition:
+ 'BFS explores nodes in waves outward from the root. Using a queue ensures we process nodes in the order they were discovered - first in, first out (FIFO). This naturally produces level-order traversal.',
+ code: {
+ language: 'python',
+ code: `def bfs(root):
+ if not root:
+ return []
+
+ result = []
+ queue = [root]
+
+ while queue:
+ # Dequeue front node
+ node = queue.pop(0)
+ result.append(node.val)
+
+ # Enqueue children (left first, then right)
+ if node.left:
+ queue.append(node.left)
+ if node.right:
+ queue.append(node.right)
+
+ return result`,
+ },
+ initialExample: {
+ input: { tree: [4, 2, 6, 1, 3, 5, 7] },
+ expected: [4, 2, 6, 1, 3, 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 level by level, from left to right at each level.',
+ dataState: {
+ arrays: [],
+ pointers: [],
+ variables: [],
+ calculations: [],
+ trees: [createTreeState({})],
+ queues: [createQueueState([])],
+ },
+ },
+ {
+ id: 'problem-2',
+ phase: 'problem',
+ explanation:
+ 'For this tree: Level 0 has [4], Level 1 has [2, 6], Level 2 has [1, 3, 5, 7]. Expected output: [4, 2, 6, 1, 3, 5, 7].',
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'highlighted', [NODE_2]: 'visiting', [NODE_6]: 'visiting' })],
+ queues: [createQueueState([])],
+ },
+ },
+
+ // ==========================================
+ // Phase 2: Intuition (3 steps)
+ // ==========================================
+ {
+ id: 'intuition-1',
+ phase: 'intuition',
+ explanation:
+ 'BFS uses a queue (FIFO). We start by adding the root, then repeatedly: dequeue one node, add its value to result, and enqueue its children.',
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'current' })],
+ queues: [createQueueState([4])],
+ },
+ },
+ {
+ id: 'intuition-2',
+ phase: 'intuition',
+ explanation:
+ 'The queue acts as a "to-visit" list. When we dequeue a node, its children join the back of the queue. This ensures we finish each level before starting the next.',
+ dataState: {
+ arrays: [createOutputState([4, null, null, null, null, null, null], 0)],
+ pointers: [],
+ variables: [],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'current', [NODE_6]: 'visiting' })],
+ queues: [createQueueState([2, 6], true)],
+ },
+ },
+ {
+ id: 'intuition-3',
+ phase: 'intuition',
+ explanation:
+ 'Key insight: nodes discovered first are processed first (FIFO). A node\'s children are always behind other nodes at the same level in the queue.',
+ dataState: {
+ arrays: [createOutputState([4, 2, null, null, null, null, null])],
+ pointers: [],
+ variables: [],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_6]: 'current', [NODE_1]: 'visiting', [NODE_3]: 'visiting' })],
+ queues: [createQueueState([6, 1, 3], true)],
+ },
+ },
+
+ // ==========================================
+ // Phase 3: Pattern (2 steps)
+ // ==========================================
+ {
+ id: 'pattern-1',
+ phase: 'pattern',
+ explanation:
+ 'BFS pattern: (1) Initialize queue with root, (2) While queue not empty: dequeue, process, enqueue children.',
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [],
+ calculations: [],
+ trees: [createTreeState({})],
+ queues: [createQueueState([])],
+ },
+ },
+ {
+ id: 'pattern-2',
+ phase: 'pattern',
+ explanation:
+ 'The queue ensures level-order: all Level N nodes are processed before any Level N+1 nodes, because children are always added to the rear.',
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [
+ { id: 'queue', name: 'queue', value: 'FIFO' },
+ { id: 'result', name: 'result', value: '[]' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'current' })],
+ queues: [createQueueState([4])],
+ },
+ },
+
+ // ==========================================
+ // Phase 4: Code (3 steps)
+ // ==========================================
+ {
+ id: 'code-1',
+ phase: 'code',
+ explanation:
+ 'Initialize: empty result list, queue 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' })],
+ queues: [createQueueState([4])],
+ },
+ },
+ {
+ id: 'code-2',
+ phase: 'code',
+ explanation:
+ 'Main loop: While queue is not empty, dequeue the front 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' })],
+ queues: [createQueueState([])],
+ },
+ },
+ {
+ id: 'code-3',
+ phase: 'code',
+ explanation:
+ 'After processing a node, enqueue its left child (if exists), then right child (if exists). This maintains left-to-right order within each level.',
+ 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' })],
+ queues: [createQueueState([2, 6], false, true)],
+ },
+ },
+
+ // ==========================================
+ // Phase 5: Execution (12 steps)
+ // ==========================================
+ {
+ id: 'exec-1',
+ phase: 'execution',
+ explanation:
+ 'Start: queue = [4], result = []. The root node is ready to be processed.',
+ codeLine: 7,
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [
+ { id: 'result', name: 'result', value: '[]' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'current' })],
+ queues: [createQueueState([4], true)],
+ },
+ },
+ {
+ id: 'exec-2',
+ phase: 'execution',
+ explanation:
+ 'Dequeue 4 (the root). Add to result. Result: [4]. Now enqueue its children: 2 (left), 6 (right).',
+ 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' })],
+ queues: [createQueueState([2, 6], false, true)],
+ },
+ },
+ {
+ id: 'exec-3',
+ phase: 'execution',
+ explanation:
+ 'Queue: [2, 6]. Dequeue 2 (front). Add to result. Result: [4, 2]. Enqueue children: 1, 3.',
+ 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_6]: 'visiting', [NODE_1]: 'visiting', [NODE_3]: 'visiting' })],
+ queues: [createQueueState([6, 1, 3], false, true)],
+ },
+ },
+ {
+ id: 'exec-4',
+ phase: 'execution',
+ explanation:
+ 'Queue: [6, 1, 3]. Dequeue 6 (front). Add to result. Result: [4, 2, 6]. Enqueue children: 5, 7.',
+ codeLine: 12,
+ dataState: {
+ arrays: [createOutputState([4, 2, 6, null, null, null, null], 2)],
+ pointers: [],
+ variables: [
+ { id: 'node', name: 'node', value: 6, previousValue: 2 },
+ { id: 'result', name: 'result', value: '[4, 2, 6]' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_6]: 'visited', [NODE_1]: 'visiting', [NODE_3]: 'visiting', [NODE_5]: 'visiting', [NODE_7]: 'visiting' })],
+ queues: [createQueueState([1, 3, 5, 7], false, true)],
+ },
+ },
+ {
+ id: 'exec-5',
+ phase: 'execution',
+ explanation:
+ 'Level 1 complete! Queue: [1, 3, 5, 7] - all Level 2 nodes. Dequeue 1. No children to enqueue.',
+ codeLine: 12,
+ dataState: {
+ arrays: [createOutputState([4, 2, 6, 1, null, null, null], 3)],
+ pointers: [],
+ variables: [
+ { id: 'node', name: 'node', value: 1, previousValue: 6 },
+ { id: 'result', name: 'result', value: '[4, 2, 6, 1]' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_6]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visiting', [NODE_5]: 'visiting', [NODE_7]: 'visiting' })],
+ queues: [createQueueState([3, 5, 7], true)],
+ },
+ },
+ {
+ id: 'exec-6',
+ phase: 'execution',
+ explanation:
+ 'Queue: [3, 5, 7]. Dequeue 3. Result: [4, 2, 6, 1, 3]. Node 3 is a leaf (no children).',
+ codeLine: 12,
+ dataState: {
+ arrays: [createOutputState([4, 2, 6, 1, 3, null, null], 4)],
+ pointers: [],
+ variables: [
+ { id: 'node', name: 'node', value: 3, previousValue: 1 },
+ { id: 'result', name: 'result', value: '[4, 2, 6, 1, 3]' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_6]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_5]: 'visiting', [NODE_7]: 'visiting' })],
+ queues: [createQueueState([5, 7], true)],
+ },
+ },
+ {
+ id: 'exec-7',
+ phase: 'execution',
+ explanation:
+ 'Queue: [5, 7]. Dequeue 5. Result: [4, 2, 6, 1, 3, 5]. Node 5 is a leaf (no children).',
+ codeLine: 12,
+ dataState: {
+ arrays: [createOutputState([4, 2, 6, 1, 3, 5, null], 5)],
+ pointers: [],
+ variables: [
+ { id: 'node', name: 'node', value: 5, previousValue: 3 },
+ { id: 'result', name: 'result', value: '[4, 2, 6, 1, 3, 5]' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_6]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_5]: 'visited', [NODE_7]: 'visiting' })],
+ queues: [createQueueState([7], true)],
+ },
+ },
+ {
+ id: 'exec-8',
+ phase: 'execution',
+ explanation:
+ 'Queue: [7]. Dequeue 7. Result: [4, 2, 6, 1, 3, 5, 7]. Node 7 is a leaf (no children).',
+ codeLine: 12,
+ dataState: {
+ arrays: [createOutputState([4, 2, 6, 1, 3, 5, 7], 6)],
+ pointers: [],
+ variables: [
+ { id: 'node', name: 'node', value: 7, previousValue: 5 },
+ { id: 'result', name: 'result', value: '[4, 2, 6, 1, 3, 5, 7]' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_6]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_5]: 'visited', [NODE_7]: 'visited' })],
+ queues: [createQueueState([])],
+ },
+ },
+ {
+ id: 'exec-9',
+ phase: 'execution',
+ explanation:
+ 'Queue is empty! All nodes have been visited. Final result: [4, 2, 6, 1, 3, 5, 7] - perfect level-order traversal.',
+ codeLine: 20,
+ dataState: {
+ arrays: [createOutputState([4, 2, 6, 1, 3, 5, 7])],
+ pointers: [],
+ variables: [
+ { id: 'result', name: 'result', value: '[4, 2, 6, 1, 3, 5, 7]' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_6]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_5]: 'visited', [NODE_7]: 'visited' })],
+ queues: [createQueueState([])],
+ },
+ },
+ ],
+};
diff --git a/frontend/src/content/algorithms/dfs.ts b/frontend/src/content/algorithms/dfs.ts
new file mode 100644
index 0000000..f80d5be
--- /dev/null
+++ b/frontend/src/content/algorithms/dfs.ts
@@ -0,0 +1,428 @@
+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([])],
+ },
+ },
+ ],
+};
diff --git a/frontend/src/content/algorithms/tree-traversal.ts b/frontend/src/content/algorithms/tree-traversal.ts
new file mode 100644
index 0000000..8193a96
--- /dev/null
+++ b/frontend/src/content/algorithms/tree-traversal.ts
@@ -0,0 +1,557 @@
+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
+ *
+ * Inorder traversal output: [1, 2, 3, 4, 5, 6, 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: 'traversal-stack',
+ label: 'Traversal Stack',
+ elements: values.map((v, i) => ({
+ id: `stack-${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 treeTraversalAlgorithm: AlgorithmDefinition = {
+ id: 'tree-traversal',
+ title: 'Inorder Tree Traversal (Iterative)',
+ slug: 'tree-traversal',
+ pattern: {
+ name: 'Tree Traversal',
+ description:
+ 'Use a stack to simulate recursion and traverse a binary tree in inorder (Left-Root-Right) order.',
+ },
+ problemStatement:
+ 'Given a binary search tree, traverse it in inorder (Left-Root-Right) to produce a sorted output. Use an iterative approach with an explicit stack.',
+ intuition:
+ 'Recursion implicitly uses a call stack. We can make this explicit: go left as far as possible while pushing nodes, then pop to process and move right. For a BST, this produces sorted order.',
+ code: {
+ language: 'python',
+ code: `def inorder_traversal(root):
+ result = []
+ stack = []
+ curr = root
+
+ while curr or stack:
+ # Go left as far as possible
+ while curr:
+ stack.append(curr)
+ curr = curr.left
+
+ # Pop and process
+ curr = stack.pop()
+ result.append(curr.val)
+
+ # Move to right subtree
+ curr = curr.right
+
+ return result`,
+ },
+ initialExample: {
+ input: { tree: [4, 2, 6, 1, 3, 5, 7] },
+ expected: [1, 2, 3, 4, 5, 6, 7],
+ },
+ steps: [
+ // ==========================================
+ // Phase 1: Problem (2 steps)
+ // ==========================================
+ {
+ id: 'problem-1',
+ phase: 'problem',
+ explanation:
+ 'We have a binary search tree. Our goal is to visit all nodes in inorder (Left-Root-Right), which for a BST gives us sorted output.',
+ dataState: {
+ arrays: [],
+ pointers: [],
+ variables: [],
+ calculations: [],
+ trees: [createTreeState({})],
+ stacks: [createStackState([])],
+ },
+ },
+ {
+ id: 'problem-2',
+ phase: 'problem',
+ explanation:
+ 'For this BST: visit left subtree (1, 2, 3), then root (4), then right subtree (5, 6, 7). Expected output: [1, 2, 3, 4, 5, 6, 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:
+ 'Recursion uses an implicit call stack. We can make this explicit: maintain our own stack to track nodes waiting to be processed.',
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [],
+ calculations: [],
+ trees: [createTreeState({})],
+ stacks: [createStackState([])],
+ },
+ },
+ {
+ id: 'intuition-2',
+ phase: 'intuition',
+ explanation:
+ 'Pattern: Starting from any node, go left as far as possible, pushing each node to the stack. When you can\'t go left, pop and process, then move right.',
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'current', [NODE_2]: 'visiting', [NODE_1]: 'visiting' })],
+ stacks: [createStackState([])],
+ },
+ },
+ {
+ id: 'intuition-3',
+ phase: 'intuition',
+ explanation:
+ 'The stack remembers ancestors waiting for their right subtrees to be processed. This mimics how recursion unwinds.',
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visiting', [NODE_2]: 'visiting', [NODE_1]: 'current' })],
+ stacks: [createStackState([4, 2], true)],
+ },
+ },
+
+ // ==========================================
+ // Phase 3: Pattern (2 steps)
+ // ==========================================
+ {
+ id: 'pattern-1',
+ phase: 'pattern',
+ explanation:
+ 'The iterative pattern has three repeating phases: (1) Go left and push, (2) Pop and process, (3) Move right.',
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [],
+ calculations: [],
+ trees: [createTreeState({})],
+ stacks: [createStackState([])],
+ },
+ },
+ {
+ id: 'pattern-2',
+ phase: 'pattern',
+ explanation:
+ 'We continue while either curr points to a node OR the stack is non-empty. Both conditions must be false to terminate.',
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 'node' },
+ { id: 'stack', name: 'stack', value: '[]' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'current' })],
+ stacks: [createStackState([])],
+ },
+ },
+
+ // ==========================================
+ // Phase 4: Code (3 steps)
+ // ==========================================
+ {
+ id: 'code-1',
+ phase: 'code',
+ explanation:
+ 'Initialize: empty result array, empty stack, and curr pointing to root.',
+ codeLine: 2,
+ codeHighlightLines: [2, 3, 4],
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 'root (4)' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'current' })],
+ stacks: [createStackState([])],
+ },
+ },
+ {
+ id: 'code-2',
+ phase: 'code',
+ explanation:
+ 'Inner while loop: Go left as far as possible, pushing each node. This processes the left subtree first.',
+ codeLine: 8,
+ codeHighlightLines: [8, 9, 10],
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visiting', [NODE_2]: 'visiting', [NODE_1]: 'current' })],
+ stacks: [createStackState([4, 2])],
+ },
+ },
+ {
+ id: 'code-3',
+ phase: 'code',
+ explanation:
+ 'After going left, pop from stack, add value to result, then move to right child.',
+ codeLine: 13,
+ codeHighlightLines: [13, 14, 17],
+ dataState: {
+ arrays: [createOutputState([1, null, null, null, null, null], 0)],
+ pointers: [],
+ variables: [],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visiting', [NODE_2]: 'current', [NODE_1]: 'visited' })],
+ stacks: [createStackState([4])],
+ },
+ },
+
+ // ==========================================
+ // Phase 5: Execution (14 steps)
+ // ==========================================
+ {
+ id: 'exec-1',
+ phase: 'execution',
+ explanation:
+ 'Start: curr = 4 (root), stack = []. The outer loop condition "curr or stack" is true.',
+ codeLine: 6,
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 4 },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'current' })],
+ stacks: [createStackState([])],
+ },
+ },
+ {
+ id: 'exec-2',
+ phase: 'execution',
+ explanation:
+ 'Go left: Push 4 to stack, move curr to left child (2). Stack: [4]',
+ codeLine: 9,
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 2, previousValue: 4 },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visiting', [NODE_2]: 'current' })],
+ stacks: [createStackState([4], true)],
+ },
+ },
+ {
+ id: 'exec-3',
+ phase: 'execution',
+ explanation:
+ 'Continue left: Push 2 to stack, move curr to left child (1). Stack: [4, 2]',
+ codeLine: 9,
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 1, previousValue: 2 },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visiting', [NODE_2]: 'visiting', [NODE_1]: 'current' })],
+ stacks: [createStackState([4, 2], true)],
+ },
+ },
+ {
+ id: 'exec-4',
+ phase: 'execution',
+ explanation:
+ 'Push 1 to stack, move curr to left child (null). Stack: [4, 2, 1]. Can\'t go left anymore.',
+ codeLine: 9,
+ dataState: {
+ arrays: [createOutputState([null, null, null, null, null, null, null])],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 'null', previousValue: 1 },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visiting', [NODE_2]: 'visiting', [NODE_1]: 'visiting' })],
+ stacks: [createStackState([4, 2, 1], true)],
+ },
+ },
+ {
+ id: 'exec-5',
+ phase: 'execution',
+ explanation:
+ 'Pop 1 from stack, add to result. Output: [1]. Move to right child of 1 (null).',
+ codeLine: 14,
+ dataState: {
+ arrays: [createOutputState([1, null, null, null, null, null, null], 0)],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 'null' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visiting', [NODE_2]: 'visiting', [NODE_1]: 'visited' })],
+ stacks: [createStackState([4, 2])],
+ },
+ },
+ {
+ id: 'exec-6',
+ phase: 'execution',
+ explanation:
+ 'curr is null but stack is non-empty. Pop 2 from stack, add to result. Output: [1, 2]. Move to right child (3).',
+ codeLine: 14,
+ dataState: {
+ arrays: [createOutputState([1, 2, null, null, null, null, null], 1)],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 3, previousValue: 'null' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visiting', [NODE_2]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'current' })],
+ stacks: [createStackState([4])],
+ },
+ },
+ {
+ id: 'exec-7',
+ phase: 'execution',
+ explanation:
+ 'At node 3. Go left: Push 3 to stack, move to left child (null). Stack: [4, 3]',
+ codeLine: 9,
+ dataState: {
+ arrays: [createOutputState([1, 2, null, null, null, null, null])],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 'null', previousValue: 3 },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visiting', [NODE_2]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visiting' })],
+ stacks: [createStackState([4, 3], true)],
+ },
+ },
+ {
+ id: 'exec-8',
+ phase: 'execution',
+ explanation:
+ 'Pop 3 from stack, add to result. Output: [1, 2, 3]. Move to right child (null).',
+ codeLine: 14,
+ dataState: {
+ arrays: [createOutputState([1, 2, 3, null, null, null, null], 2)],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 'null' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visiting', [NODE_2]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited' })],
+ stacks: [createStackState([4])],
+ },
+ },
+ {
+ id: 'exec-9',
+ phase: 'execution',
+ explanation:
+ 'Pop 4 from stack (the root!), add to result. Output: [1, 2, 3, 4]. Move to right child (6).',
+ codeLine: 14,
+ dataState: {
+ arrays: [createOutputState([1, 2, 3, 4, null, null, null], 3)],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 6, previousValue: 'null' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_6]: 'current' })],
+ stacks: [createStackState([])],
+ },
+ },
+ {
+ id: 'exec-10',
+ phase: 'execution',
+ explanation:
+ 'At node 6. Go left: Push 6 to stack, move to left child (5). Stack: [6]',
+ codeLine: 9,
+ dataState: {
+ arrays: [createOutputState([1, 2, 3, 4, null, null, null])],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 5, previousValue: 6 },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_6]: 'visiting', [NODE_5]: 'current' })],
+ stacks: [createStackState([6], true)],
+ },
+ },
+ {
+ id: 'exec-11',
+ phase: 'execution',
+ explanation:
+ 'At node 5. Go left: Push 5 to stack, move to left child (null). Stack: [6, 5]',
+ codeLine: 9,
+ dataState: {
+ arrays: [createOutputState([1, 2, 3, 4, null, null, null])],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 'null', previousValue: 5 },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_6]: 'visiting', [NODE_5]: 'visiting' })],
+ stacks: [createStackState([6, 5], true)],
+ },
+ },
+ {
+ id: 'exec-12',
+ phase: 'execution',
+ explanation:
+ 'Pop 5 from stack, add to result. Output: [1, 2, 3, 4, 5]. Move to right child (null).',
+ codeLine: 14,
+ dataState: {
+ arrays: [createOutputState([1, 2, 3, 4, 5, null, null], 4)],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 'null' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_6]: 'visiting', [NODE_5]: 'visited' })],
+ stacks: [createStackState([6])],
+ },
+ },
+ {
+ id: 'exec-13',
+ phase: 'execution',
+ explanation:
+ 'Pop 6 from stack, add to result. Output: [1, 2, 3, 4, 5, 6]. Move to right child (7).',
+ codeLine: 14,
+ dataState: {
+ arrays: [createOutputState([1, 2, 3, 4, 5, 6, null], 5)],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 7, previousValue: 'null' },
+ ],
+ calculations: [],
+ trees: [createTreeState({ [NODE_4]: 'visited', [NODE_2]: 'visited', [NODE_1]: 'visited', [NODE_3]: 'visited', [NODE_6]: 'visited', [NODE_5]: 'visited', [NODE_7]: 'current' })],
+ stacks: [createStackState([])],
+ },
+ },
+ {
+ id: 'exec-14',
+ phase: 'execution',
+ explanation:
+ 'At node 7. Go left: Push 7 to stack, move to left child (null). Stack: [7]',
+ codeLine: 9,
+ dataState: {
+ arrays: [createOutputState([1, 2, 3, 4, 5, 6, null])],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 'null', previousValue: 7 },
+ ],
+ 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-15',
+ phase: 'execution',
+ explanation:
+ 'Pop 7 from stack, add to result. Output: [1, 2, 3, 4, 5, 6, 7]. Move to right child (null).',
+ codeLine: 14,
+ dataState: {
+ arrays: [createOutputState([1, 2, 3, 4, 5, 6, 7], 6)],
+ pointers: [],
+ variables: [
+ { id: 'curr', name: 'curr', value: 'null' },
+ ],
+ 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-16',
+ phase: 'execution',
+ explanation:
+ 'Done! curr is null AND stack is empty. Final output: [1, 2, 3, 4, 5, 6, 7] - the BST values in sorted order.',
+ codeLine: 19,
+ dataState: {
+ arrays: [createOutputState([1, 2, 3, 4, 5, 6, 7])],
+ pointers: [],
+ variables: [
+ { id: 'result', name: 'result', value: '[1, 2, 3, 4, 5, 6, 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([])],
+ },
+ },
+ ],
+};
diff --git a/frontend/src/lib/visualizations/types.ts b/frontend/src/lib/visualizations/types.ts
index 5639aae..2d114a5 100644
--- a/frontend/src/lib/visualizations/types.ts
+++ b/frontend/src/lib/visualizations/types.ts
@@ -82,6 +82,10 @@ export interface DataState {
linkedListPointers?: LinkedListPointerState[];
// Stack support
stacks?: StackState[];
+ // Tree support
+ trees?: BinaryTreeState[];
+ // Queue support
+ queues?: QueueState[];
}
/** Single step in the visualization */
@@ -203,3 +207,42 @@ export interface StackState {
elements: StackElementState[];
label?: string;
}
+
+// ============================================
+// Binary Tree Types
+// ============================================
+
+/** State of a binary tree node */
+export interface BinaryTreeNodeState {
+ id: string;
+ value: number;
+ state: 'normal' | 'current' | 'visiting' | 'visited' | 'highlighted';
+ left: string | null;
+ right: string | null;
+}
+
+/** Complete binary tree state */
+export interface BinaryTreeState {
+ id: string;
+ nodes: BinaryTreeNodeState[];
+ rootId: string;
+ label?: string;
+}
+
+// ============================================
+// Queue Types
+// ============================================
+
+/** State of a queue element */
+export interface QueueElementState {
+ id: string;
+ value: number | string;
+ state: 'normal' | 'highlighted' | 'enqueued' | 'dequeued';
+}
+
+/** Complete queue state */
+export interface QueueState {
+ id: string;
+ elements: QueueElementState[];
+ label?: string;
+}