1+ /**
2+ * Morris Traversal (Inorder Traversal without recursion or stack)
3+ * Wikipedia: https://en.wikipedia.org/wiki/Threaded_binary_tree#Morris_traversal
4+ *
5+ * WHAT IS MORRIS TRAVERSAL?
6+ * Morris Traversal is a clever technique to traverse a binary tree in inorder
7+ * (Left → Root → Right) using O(1) extra space - meaning it doesn't need recursion
8+ * or an explicit stack like traditional methods.
9+ *
10+ * HOW DOES IT WORK?
11+ * The algorithm temporarily modifies the tree by creating "threads" (temporary links)
12+ * that help us navigate back to parent nodes without using extra memory.
13+ * Think of it like leaving breadcrumbs to find your way back!
14+ *
15+ * KEY CONCEPT - INORDER PREDECESSOR:
16+ * For any node, its inorder predecessor is the rightmost node in its left subtree.
17+ * This is the node that comes just before it in inorder traversal.
18+ *
19+ * ALGORITHM STEPS:
20+ * 1. Start at root, move current pointer through the tree
21+ * 2. If current node has no left child: visit it, move right
22+ * 3. If current node has left child:
23+ * a. Find the inorder predecessor (rightmost in left subtree)
24+ * b. If predecessor's right is null: create thread, go left
25+ * c. If predecessor's right points to current: remove thread, visit current, go right
26+ *
27+ * Example Tree:
28+ * 7
29+ * / \
30+ * 5 8
31+ * / \
32+ * 3 6
33+ * \
34+ * 9
35+ *
36+ * Traversal order: 3 → 5 → 6 → 9 → 7 → 8
37+ *
38+ * TIME COMPLEXITY: O(n) - each edge is traversed at most twice
39+ * SPACE COMPLEXITY: O(1) - no extra space except for result array
40+ */
41+
42+ class TreeNode {
43+ constructor ( val , left = null , right = null ) {
44+ this . val = val ;
45+ this . left = left ;
46+ this . right = right ;
47+ }
48+ }
49+
50+ function morrisTraversal ( root ) {
51+ const result = [ ] ; // Array to store the inorder traversal result
52+ let curr = root ; // Current node we're processing
53+
54+ // Continue until we've processed all nodes
55+ while ( curr ) {
56+
57+ // CASE 1: Current node has no left child
58+ // This means we can safely visit this node (no left subtree to process first)
59+ if ( ! curr . left ) {
60+ result . push ( curr . val ) ; // Visit the current node
61+ curr = curr . right ; // Move to right subtree
62+ }
63+
64+ // CASE 2: Current node has a left child
65+ // We need to find a way to come back to this node after processing left subtree
66+ else {
67+
68+ // STEP 1: Find the inorder predecessor of current node
69+ // (Rightmost node in the left subtree)
70+ let pred = curr . left ;
71+
72+ // Keep going right until we find the rightmost node
73+ // BUT stop if we find a node that already points back to curr (existing thread)
74+ while ( pred . right && pred . right !== curr ) {
75+ pred = pred . right ;
76+ }
77+
78+ // STEP 2a: If predecessor's right is null, we need to create a thread
79+ // This thread will help us return to current node later
80+ if ( ! pred . right ) {
81+ // Create the thread: make predecessor point to current node
82+ pred . right = curr ;
83+
84+ // Now go left to process the left subtree first
85+ curr = curr . left ;
86+ }
87+
88+ // STEP 2b: If predecessor's right already points to current node
89+ // This means we've already processed the left subtree and are back via the thread
90+ else {
91+ // Remove the thread (restore original tree structure)
92+ pred . right = null ;
93+
94+ // Now we can safely visit the current node
95+ result . push ( curr . val ) ;
96+
97+ // Move to right subtree
98+ curr = curr . right ;
99+ }
100+ }
101+ }
102+
103+ return result ;
104+ }
105+
106+ module . exports = { TreeNode, morrisTraversal } ;
0 commit comments