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