Morris Traversal Inorder Without Stack in DSA C - Time & Space Complexity
We analyze how the Morris Traversal method visits nodes in a binary tree without extra memory.
We want to know how the number of steps grows as the tree gets bigger.
Analyze the time complexity of the following code snippet.
void morrisInorderTraversal(Node* root) {
Node* current = root;
while (current != NULL) {
if (current->left == NULL) {
printf("%d ", current->data);
current = current->right;
} else {
Node* predecessor = current->left;
while (predecessor->right != NULL && predecessor->right != current) {
predecessor = predecessor->right;
}
if (predecessor->right == NULL) {
predecessor->right = current;
current = current->left;
} else {
predecessor->right = NULL;
printf("%d ", current->data);
current = current->right;
}
}
}
}
This code visits all nodes of a binary tree in order without using a stack or recursion.
Look at the loops and repeated steps:
- Primary operation: Moving through nodes and finding the rightmost child (predecessor) in the left subtree.
- How many times: Each edge in the tree is visited at most twice: once to create a temporary link and once to remove it.
As the tree grows, each node is visited a limited number of times.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 20 visits (each edge twice) |
| 100 | About 200 visits |
| 1000 | About 2000 visits |
Pattern observation: The total steps grow roughly twice the number of nodes, so growth is linear.
Time Complexity: O(n)
This means the time to complete the traversal grows directly in proportion to the number of nodes.
[X] Wrong: "Since there is a nested loop, the time must be quadratic O(n²)."
[OK] Correct: The inner loop does not run fully for every node; each edge is visited only twice, keeping total steps linear.
Understanding Morris Traversal shows you can optimize space while keeping time efficient, a valuable skill in coding challenges and real projects.
"What if we used recursion instead of Morris Traversal? How would the time and space complexity change?"
Practice
Solution
Step 1: Understand traditional inorder traversal space usage
Traditional inorder traversal uses recursion or a stack, which requires extra memory proportional to tree height.Step 2: Identify Morris Traversal space usage
Morris Traversal modifies tree links temporarily to avoid stack or recursion, using O(1) extra space.Final Answer:
It uses no extra space like stack or recursion -> Option CQuick Check:
Morris Traversal = O(1) space [OK]
- Thinking Morris is faster in time complexity
- Assuming it only works on BSTs
- Believing it needs special tree nodes
Solution
Step 1: Understand pointer initialization in C for tree traversal
We need a pointer to the root node to start traversal, so 'struct Node* current = root;' is correct.Step 2: Check other options for correctness
struct Node current = root; declares a struct variable, not a pointer, which is incorrect. Node* current = NULL; uses 'Node*' without 'struct' keyword, invalid in C. struct Node* current = NULL; initializes current to NULL, which won't start traversal.Final Answer:
struct Node* current = root; -> Option AQuick Check:
Pointer to root = struct Node* current = root; [OK]
- Using struct variable instead of pointer
- Omitting 'struct' keyword in C
- Initializing current to NULL instead of root
2
/ \
1 3
Assuming the traversal prints node values separated by spaces.Solution
Step 1: Understand inorder traversal order
Inorder traversal visits left subtree, then root, then right subtree. For this tree, left is 1, root is 2, right is 3.Step 2: Apply Morris traversal logic
Morris traversal visits nodes in inorder without stack. The output will be "1 2 3 " as it visits left child, root, then right child.Final Answer:
1 2 3 -> Option BQuick Check:
Inorder of tree = 1 2 3 [OK]
- Confusing preorder or postorder with inorder
- Forgetting spaces in output
- Misreading tree structure
while (current != NULL) {
if (current->left == NULL) {
printf("%d ", current->data);
current = current->right;
} else {
struct Node* pre = current->left;
while (pre->right != NULL) {
pre = pre->right;
}
pre->right = current;
current = current->left;
}
}
Solution
Step 1: Analyze inner while loop condition
The inner loop finds the rightmost node in left subtree. It should stop if pre->right points back to current to avoid infinite loop.Step 2: Identify correct condition
The condition must be 'pre->right != NULL && pre->right != current' to detect if thread already exists and avoid infinite loop.Final Answer:
The inner while loop should check pre->right != current -> Option DQuick Check:
Loop condition must detect thread to current [OK]
- Not checking pre->right != current causes infinite loop
- Forgetting to restore tree links after traversal
- Confusing recursion with Morris traversal
Solution
Step 1: Understand Morris traversal threading
Morris traversal creates temporary links (threads) from the rightmost node of left subtree back to the current node to remember where to return.Step 2: Apply to nodes with only left children
For nodes with only left children, it finds the rightmost node in left subtree (which may be the left child itself) and creates a thread back to current node, enabling traversal without stack.Final Answer:
It creates temporary threads from rightmost left child back to current node -> Option AQuick Check:
Temporary threads enable traversal without stack [OK]
- Assuming nodes without right children are skipped
- Thinking Morris uses stack internally
- Believing tree is converted to linked list
Ready to prove it?
Pass the test and this pattern moves unknown
