Discover how to explore a tree without carrying extra memory--like finding your way in a maze using only the doors themselves!
Why Morris Traversal Inorder Without Stack in DSA Go?
Imagine you want to visit every room in a big house, but you only have one key and no map. You try to remember every door you opened so you can go back, but it's easy to forget and get lost.
Using a manual method like writing down every door or carrying a stack of keys slows you down and can cause mistakes. You might lose track or run out of space to keep notes, making the whole process tiring and confusing.
Morris Traversal lets you visit every room (node) without extra memory like a stack or recursion. It cleverly uses the house's own doors (tree links) to remember where to go next, so you never get lost and don't need extra tools.
func inorderTraversal(root *Node) {
stack := []*Node{}
current := root
for current != nil || len(stack) > 0 {
for current != nil {
stack = append(stack, current)
current = current.Left
}
current = stack[len(stack)-1]
stack = stack[:len(stack)-1]
fmt.Println(current.Value)
current = current.Right
}
}func morrisInorderTraversal(root *Node) {
current := root
for current != nil {
if current.Left == nil {
fmt.Println(current.Value)
current = current.Right
} else {
predecessor := current.Left
for predecessor.Right != nil && predecessor.Right != current {
predecessor = predecessor.Right
}
if predecessor.Right == nil {
predecessor.Right = current
current = current.Left
} else {
predecessor.Right = nil
fmt.Println(current.Value)
current = current.Right
}
}
}
}This method enables efficient tree traversal using no extra memory, making it perfect for large trees or memory-limited environments.
When a robot explores a maze with limited memory, Morris Traversal helps it remember paths by temporarily marking doors, so it can explore fully without carrying a map or notes.
Morris Traversal visits nodes without extra memory like stacks or recursion.
It temporarily changes tree links to remember paths, then restores them.
This makes inorder traversal faster and more memory-efficient.
Practice
Solution
Step 1: Understand Morris Traversal space usage
Morris Traversal modifies the tree temporarily to avoid using stack or recursion, so it uses O(1) extra space.Step 2: Compare with other methods
Traditional inorder traversal uses recursion or stack which requires O(h) space, where h is tree height.Final Answer:
It uses no extra space for stack or recursion -> Option DQuick Check:
Morris Traversal = O(1) space [OK]
- Thinking it is faster than all methods
- Assuming it only works on BSTs
- Believing it needs balanced trees
Solution
Step 1: Understand pointer initialization
For traversal, current should start at root node, so current := root is correct.Step 2: Check other options
var current *Node = nil sets current to nil, which stops traversal immediately. current := &root takes address of root pointer, incorrect. current := root.left starts at left child, skipping root.Final Answer:
current := root -> Option AQuick Check:
Start traversal at root = current := root [OK]
- Initializing current as nil
- Taking address of root pointer
- Starting at root.left instead of root
2
/ \
1 3
func morrisInorder(root *Node) {
current := root
for current != nil {
if current.Left == nil {
fmt.Print(current.Val, " ")
current = current.Right
} else {
pre := current.Left
for pre.Right != nil && pre.Right != current {
pre = pre.Right
}
if pre.Right == nil {
pre.Right = current
current = current.Left
} else {
pre.Right = nil
fmt.Print(current.Val, " ")
current = current.Right
}
}
}
}Solution
Step 1: Understand inorder traversal order
Inorder traversal visits left subtree, root, then right subtree. For tree 2 with left 1 and right 3, order is 1 2 3.Step 2: Trace Morris traversal output
Morris traversal prints nodes in inorder without stack. The code prints 1, then 2, then 3 with spaces.Final Answer:
1 2 3 -> Option BQuick Check:
Inorder of given tree = 1 2 3 [OK]
- Confusing preorder or postorder output
- Misreading the tree structure
- Ignoring Morris threading logic
current := root
for current != nil {
if current.Left != nil {
pre := current.Left
for pre.Right != nil {
pre = pre.Right
}
pre.Right = current
current = current.Left
} else {
fmt.Print(current.Val, " ")
current = current.Right
}
}Solution
Step 1: Analyze inner loop for threading
The inner loop finds rightmost node of left subtree. Without checking if pre.Right == current, it keeps looping infinitely.Step 2: Identify missing condition causing infinite loop
Correct Morris traversal checks if pre.Right is nil or points to current to avoid infinite loop. Missing this causes infinite loop.Final Answer:
Missing check if pre.Right == current before setting pre.Right = current -> Option CQuick Check:
Check pre.Right == current to avoid loops [OK]
- Skipping pre.Right == current check
- Wrong pointer updates
- Printing too early
Solution
Step 1: Identify when nodes are visited in Morris traversal
Nodes are printed exactly once: when current.Left == nil or when removing the thread (pre.Right != nil).Step 2: Choose correct increment point for counting
Incrementing the counter each time a node's value is printed ensures every node is counted exactly once.Final Answer:
Add a counter variable and increment it each time you print a node's value during traversal -> Option AQuick Check:
Increment on every print operation [OK]
- Incrementing only when current.Left is nil (misses nodes with left subtrees)
- Incrementing when creating threads (counts only non-leaf nodes)
- Incrementing when removing threads (counts only non-leaf nodes)
Ready to prove it?
Pass the test and this pattern moves unknown
