Morris Traversal Inorder Without Stack in DSA Python - Time & Space Complexity
We want to understand how the Morris Traversal method for inorder tree traversal performs as the tree size grows.
Specifically, how many steps does it take to visit all nodes without using extra memory for a stack?
Analyze the time complexity of the following Morris Inorder Traversal code.
def morris_inorder(root):
current = root
while current:
if not current.left:
print(current.val)
current = current.right
else:
pre = current.left
while pre.right and pre.right != current:
pre = pre.right
if not pre.right:
pre.right = current
current = current.left
else:
pre.right = None
print(current.val)
current = current.right
This code visits all nodes of a binary tree in inorder without using a stack or recursion by temporarily modifying pointers.
Look for loops and repeated steps in the code.
- Primary operation: The outer while loop runs as long as there is a current node.
- Nested operation: The inner while loop finds the rightmost node in the left subtree (predecessor).
- How many times: Each edge in the tree is visited at most twice because the traversal creates and removes temporary links.
As the number of nodes (n) increases, the traversal visits each node and its edges a limited number of times.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 20 visits (nodes and edges) |
| 100 | About 200 visits |
| 1000 | About 2000 visits |
Pattern observation: The number of operations grows roughly twice the number of nodes, so it grows linearly.
Time Complexity: O(n)
This means the traversal time grows directly in proportion to the number of nodes in the tree.
[X] Wrong: "Because of the nested while loop, the time complexity must be O(n²)."
[OK] Correct: The inner loop does not run fully for every node; it only moves along edges that are visited at most twice, keeping total work linear.
Understanding Morris Traversal shows you can traverse trees efficiently without extra memory, a skill that impresses by combining clever pointer use and time efficiency.
"What if we used recursion instead of Morris Traversal? How would the time and space complexity change?"
Practice
Solution
Step 1: Understand Morris Traversal space usage
Morris Traversal uses threaded binary trees to avoid recursion or stack, 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 AQuick Check:
Space complexity = O(1) [OK]
- Thinking Morris is faster in time complexity
- Believing it only works on BSTs
- Assuming it permanently changes the tree
Solution
Step 1: Identify starting point for traversal
Morris traversal starts from the root node to cover the entire tree.Step 2: Check initialization options
Setting current = root ensures traversal begins at the tree's root.Final Answer:
current = root -> Option AQuick Check:
Start at root node [OK]
- Starting from None causes no traversal
- Starting from root.left misses root node
- Starting from root.right misses left subtree
2
/ \
1 3
Assuming the traversal prints node values in order.Solution
Step 1: Understand inorder traversal order
Inorder traversal visits left subtree, root, then right subtree.Step 2: Apply Morris traversal order
For the tree, left is 1, root is 2, right is 3, so output is [1, 2, 3].Final Answer:
[1, 2, 3] -> Option DQuick Check:
Inorder = left-root-right = [1, 2, 3] [OK]
- Confusing preorder or postorder with inorder
- Misreading tree structure
- Assuming traversal prints in insertion order
current = root
while current:
if current.left is None:
print(current.val)
current = current.right
else:
pre = current.left
while pre.right and pre.right != current:
pre = pre.right
if pre.right is None:
pre.right = current
current = current.left
else:
pre.right = None
print(current.val)
current = current.right
What is the main bug if the line pre.right = None is missing?Solution
Step 1: Understand role of
This line removes the temporary thread created to return to the root after left subtree traversal.pre.right = NoneStep 2: Consequence of missing this line
If not removed, the thread remains, causing the loop to revisit nodes endlessly, creating an infinite loop.Final Answer:
The traversal will enter an infinite loop. -> Option CQuick Check:
Missing thread removal = infinite loop [OK]
- Thinking it causes syntax error
- Assuming it changes traversal order
- Believing it skips nodes
result = []
current = root
while current:
if current.left is None:
# Change here
current = current.right
else:
pre = current.left
while pre.right and pre.right != current:
pre = pre.right
if pre.right is None:
pre.right = current
current = current.left
else:
pre.right = None
# Change here
current = current.right
Solution
Step 1: Identify where nodes are visited
In Morris traversal, nodes are visited and printed in two places: when left is None and after removing thread.Step 2: Replace print with appending to list
To collect values, replace both print statements withresult.append(current.val)to capture all visited nodes.Final Answer:
Replace both '# Change here' lines with result.append(current.val) -> Option BQuick Check:
Collect all visited nodes in list [OK]
- Appending only once misses some nodes
- Leaving print statements causes unwanted output
- Changing traversal logic breaks correctness
Ready to prove it?
Pass the test and this pattern moves unknown
