Discover how to walk through a tree without carrying extra memory or getting lost!
Why Morris Traversal Inorder Without Stack in DSA C++?
Imagine you want to walk through a maze (a tree) and note down every room (node) you visit in order. Without a map or a helper (stack), you try to remember every turn you took. It quickly becomes confusing and you might get lost or repeat rooms.
Using a stack or recursion to remember your path takes extra memory and can slow you down. If the maze is huge, carrying this memory is heavy and inefficient. Also, managing this memory manually can cause mistakes and crashes.
Morris Traversal cleverly uses the maze itself to mark your path temporarily. It creates small shortcuts (temporary links) so you can walk through all rooms in order without extra memory. After visiting, it cleans up these shortcuts, leaving the maze unchanged.
void inorderTraversal(Node* root) {
std::stack<Node*> nodeStack;
Node* current = root;
while (current != nullptr || !nodeStack.empty()) {
while (current != nullptr) {
nodeStack.push(current);
current = current->left;
}
current = nodeStack.top();
nodeStack.pop();
std::cout << current->data << " ";
current = current->right;
}
}void morrisInorderTraversal(Node* root) {
Node* current = root;
while (current != nullptr) {
if (current->left == nullptr) {
std::cout << current->data << " ";
current = current->right;
} else {
Node* predecessor = current->left;
while (predecessor->right != nullptr && predecessor->right != current) {
predecessor = predecessor->right;
}
if (predecessor->right == nullptr) {
predecessor->right = current;
current = current->left;
} else {
predecessor->right = nullptr;
std::cout << current->data << " ";
current = current->right;
}
}
}
}This method enables you to traverse a binary tree in order using only constant extra space, making it efficient for large trees or memory-limited environments.
Think of exploring a large library where you want to read every book in order without carrying a big notebook or asking for help. Morris Traversal is like using bookmarks inside the books themselves to remember where you left off.
Morris Traversal avoids extra memory by temporarily modifying the tree.
It visits nodes in inorder sequence without stack or recursion.
After traversal, the tree structure is restored to original.
Practice
Solution
Step 1: Understand Morris Traversal space usage
Morris Traversal does not use recursion or an explicit stack, instead it temporarily modifies the tree's right pointers to traverse.Step 2: Compare with traditional methods
Traditional inorder traversal uses recursion or a stack, which requires extra memory proportional to tree height.Final Answer:
It uses no extra space for stack or recursion, only modifies tree temporarily -> Option DQuick Check:
Space efficiency = No extra stack [OK]
- Thinking Morris sorts nodes
- Assuming it needs a binary search tree
- Believing it uses threads or parallelism
Solution
Step 1: Understand pointer usage in C++ for tree traversal
We need a pointer to traverse nodes, so current should be a pointer to Node initialized to root pointer.Step 2: Analyze options
Node* current = root; correctly declares a pointer and assigns root. Options B and D declare objects, not pointers. Node* current = new Node(root); incorrectly uses new with root pointer.Final Answer:
Node* current = root; -> Option BQuick Check:
Pointer initialization = Node* current = root [OK]
- Declaring current as object instead of pointer
- Using new operator incorrectly
- Dereferencing root without pointer
struct Node {
int data;
Node* left;
Node* right;
};
void morrisInorder(Node* root) {
Node* current = root;
while (current != nullptr) {
if (current->left == nullptr) {
std::cout << current->data << " ";
current = current->right;
} else {
Node* pre = current->left;
while (pre->right != nullptr && pre->right != current) {
pre = pre->right;
}
if (pre->right == nullptr) {
pre->right = current;
current = current->left;
} else {
pre->right = nullptr;
std::cout << current->data << " ";
current = current->right;
}
}
}
}
// Tree: 1
// / \
// 2 3
int main() {
Node n1{1, nullptr, nullptr};
Node n2{2, nullptr, nullptr};
Node n3{3, nullptr, nullptr};
n1.left = &n2;
n1.right = &n3;
morrisInorder(&n1);
return 0;
}Solution
Step 1: Understand inorder traversal order
Inorder traversal visits left subtree, then root, then right subtree. For tree 1 with left 2 and right 3, order is 2, 1, 3.Step 2: Trace Morris traversal output
Morris traversal prints nodes in inorder without stack. It prints 2 first (left child), then 1 (root), then 3 (right child).Final Answer:
2 1 3 -> Option CQuick Check:
Inorder output = 2 1 3 [OK]
- Confusing preorder or postorder output
- Ignoring temporary link restoration
- Assuming output is sorted only for BST
void morrisInorder(Node* root) {
Node* current = root;
while (current != nullptr) {
if (current->left == nullptr) {
std::cout << current->data << " ";
current = current->right;
} else {
Node* pre = current->left;
while (pre->right != nullptr) {
pre = pre->right;
}
if (pre->right == nullptr) {
pre->right = current;
current = current->left;
} else {
pre->right = nullptr;
std::cout << current->data << " ";
current = current->right;
}
}
}
}Solution
Step 1: Analyze inner while loop condition
The inner while loop should check if pre->right is not nullptr and not equal to current to avoid infinite loop.Step 2: Identify missing condition causing infinite loop
Missing check pre->right != current causes loop to never break when pre->right points back to current, causing infinite loop.Final Answer:
The inner while loop misses checking pre->right != current causing infinite loop -> Option AQuick Check:
Loop condition must check pre->right != current [OK]
- Ignoring second condition in inner loop
- Forgetting to update current after printing
- Not handling empty tree
void morrisCount(Node* root) {
int count = 0;
Node* current = root;
while (current != nullptr) {
if (current->left == nullptr) {
count++;
current = current->right;
} else {
Node* pre = current->left;
while (pre->right != nullptr && pre->right != current) {
pre = pre->right;
}
if (pre->right == nullptr) {
pre->right = current;
current = current->left;
} else {
pre->right = nullptr;
count++;
current = current->right;
}
}
}
std::cout << count << std::endl;
}Solution
Step 1: Understand counting during Morris traversal
Count nodes when visiting them: when left is nullptr or after restoring links (pre->right == current).Step 2: Verify code increments count correctly
Code increments count in both cases correctly, so it counts all nodes without extra space or recursion.Final Answer:
This code correctly counts nodes using Morris traversal without extra space -> Option AQuick Check:
Count increments on node visit = correct [OK]
- Counting only once per node visit
- Making count global unnecessarily
- Assuming Morris can't count nodes
Ready to prove it?
Pass the test and this pattern moves unknown
