Trees · Binary Tree Fundamentals

Morris Threaded Traversal

Traversing a tree in O(1) extra space by temporarily rewiring a node's inorder predecessor to point back to it (a "thread"), using that thread to return to the node later without a stack or recursion, then removing the thread once it's served its purpose.

  • 6 min read
  • 10 practice questions
  • 2 graded problems
On this page
  1. Description
  2. The approach (inorder; preorder is a one-line change)
  3. Where you'll see it
  4. Which tool for which job?
  5. Common mistakes
  6. Check yourself
  7. Key takeaways
  8. Quick revise
  9. Practice

Description

Morris traversal walks a binary tree in order using O(1) extra space: no recursion, no stack. Before going down a node's left subtree, it makes that subtree's rightmost node point back to the node. That temporary link is called a "thread", and it lets the walk find its way back. When the walk returns along the thread, it removes it. It's the answer when the interviewer says "now without the stack".

We'll go from simple to more technical:

  1. The pattern: thread, descend, come back, unthread.
  2. Inorder versus preorder: the same loop, a different moment to visit.
  3. Where borrowing an unused pointer saves real memory.
  4. The risks: threads left behind, and mutating a tree others can see.

The approach (inorder; preorder is a one-line change)

Recursion remembers "come back here after the left subtree" on the call stack: O(h) extra space, where h is the tree's height. Morris stores that reminder inside the tree instead. In inorder, the last node visited in a node's left subtree is that subtree's rightmost node, the node's predecessor. The predecessor has no right child, so its right pointer is free. Point it at the current node, go left, and when the walk later arrives through that pointer, you know the left side is done.

4

2

6

1

3

4

2

6

1

3

AtWhat happensVisited so far
4its predecessor is 3: thread 3 to 4, go left
2its predecessor is 1: thread 1 to 2, go left
1no left child: visit, follow the thread to 21
2the thread is there, so the left side is done: remove it, visit, go right1 2
3no left child: visit, follow the thread to 41 2 3
4the thread is there: remove it, visit, go right1 2 3 4
6no left child: visit, go right to null and stop1 2 3 4 6

Java

TreeNode curr = root;
while (curr != null) {
    if (curr.left == null) {
        visit(curr);              // no left subtree - visit now, move right
        curr = curr.right;
    } else {
        TreeNode pred = curr.left;
        while (pred.right != null && pred.right != curr) pred = pred.right;  // find predecessor
        if (pred.right == null) {
            pred.right = curr;     // create the thread
            curr = curr.left;      // descend, without visiting curr yet (inorder: node comes after left)
        } else {
            pred.right = null;     // thread already exists - we've returned via it; remove it
            visit(curr);            // now visit curr (its left subtree is done)
            curr = curr.right;
        }
    }
}

Python

curr = root
while curr is not None:
    if curr.left is None:
        visit(curr)              # no left subtree - visit now, move right
        curr = curr.right
    else:
        pred = curr.left
        while pred.right is not None and pred.right is not curr:
            pred = pred.right    # find predecessor
        if pred.right is None:
            pred.right = curr    # create the thread
            curr = curr.left     # descend, without visiting curr yet (inorder: node comes after left)
        else:
            pred.right = None    # thread already exists - we've returned via it; remove it
            visit(curr)          # now visit curr (its left subtree is done)
            curr = curr.right

For preorder, visit curr when you create the thread, before going left, instead of when you remove it. Nothing else changes.

Where you'll see it

O(1) space matters on small embedded devices. It also matters when many separate trees are walked at once, so stack space adds up. When "no stack, no recursion" is a hard rule rather than a preference, Morris is the standard answer.

Which tool for which job?

You needUse
Inorder or preorder, simplestrecursion
The same on a very deep treean explicit stack
The same with O(1) extra spaceMorris traversal
A tree others may read meanwhilenot Morris - it mutates the tree
Early exit (k-th smallest) with Morrisfinish the walk or undo the threads
Postorder in O(1) spacepossible, but rarely worth it

Common mistakes

MistakeWhat happensDo this instead
Not removing the threadthe tree keeps phantom linkspred.right = null on the way back
Visiting at the wrong momentpreorder instead of inorder (or the reverse)inorder visits when unthreading
Returning early mid-traversalthreads stay in the treefinish, or clean up before returning
Searching for the predecessor without the != cur checkan infinite loop around the threadstop at null or at cur
Using it on shared or read-only treesother readers see a broken treeuse a stack

Check yourself

Try to answer before opening each one - recalling beats re-reading.

1. An implementation creates threads but never removes them. What state is the tree in afterwards?

Show answer

Broken. Every predecessor that got a thread still points back up at an ancestor instead of at null. Any later walk that follows right pointers takes those links and gives wrong results, with no error to warn you.

2. What single change turns Morris inorder into Morris preorder?

Show answer

When the node is visited. Preorder visits it when the thread is created, before going left. Inorder visits it when the thread is removed, after the left subtree is done. Every other line is the same.

3. Why does the predecessor search also stop at pred.right == curr, not just at null?

Show answer

On the way back, the predecessor's right is the thread to curr. A search that stopped only at null would follow the thread onto curr and keep going, threading again and looping forever. Stopping on the thread lets the next check tell the two visits apart: null means create the thread, anything else means remove it.

Key takeaways

  • Morris borrows the predecessor's unused right pointer as a "come back here" link, so no stack is needed.
  • Remove every thread on the way back, or the tree stays broken.
  • Inorder visits when removing the thread; preorder visits when creating it.
  • The predecessor search stops at null or at curr.
  • O(1) space costs a temporarily changed tree and trickier code. Use it when the space limit is real.

Quick revise

The whole skill on one page, for the night before an interview.

Everything from the lesson and the deep dive on one page. Skim it before practice or an interview, and open the full lesson for anything that doesn't ring a bell.

Pick the tool

You needUse
Simplerecursion
Deep treesan explicit stack
O(1) extra spaceMorris
Shared / read-only treesnot Morris

Snippets worth knowing by heart

Java

TreeNode cur = root;
while (cur != null) {
    if (cur.left == null) { visit(cur); cur = cur.right; }
    else {
        TreeNode pred = cur.left;
        while (pred.right != null && pred.right != cur) pred = pred.right;
        if (pred.right == null) { pred.right = cur; cur = cur.left; }      // thread (preorder: visit here)
        else { pred.right = null; visit(cur); cur = cur.right; }           // unthread, inorder visit
    }
}

Python

cur = root
while cur:
    if cur.left is None:
        visit(cur)
        cur = cur.right
    else:
        pred = cur.left
        while pred.right and pred.right is not cur:
            pred = pred.right
        if pred.right is None:
            pred.right, cur = cur, cur.left          # thread
        else:
            pred.right = None                        # unthread
            visit(cur)
            cur = cur.right

The traps

  • Threads not removed: the tree keeps phantom links. Set pred.right = null on the way back.
  • The wrong visit moment: you get preorder instead of inorder. Inorder visits when unthreading.
  • Early return: threads stay in the tree. Finish the walk, or clean up first.
  • No != cur check: the predecessor search loops around the thread forever. Stop at null or at cur.
  • Shared trees: other readers see a broken tree mid-walk. Use a stack instead.

Staff-level points, one line each

  • 3.5 pointer moves per node on a random BST, 4.0 on a chain - O(n).
  • Recursive inorder on a 200,000-node chain: StackOverflowError; Morris: fine.
  • Early exit at the 3rd smallest left 2 links changed.
  • Needs exclusive access; slower than a stack in practice.

Say it in an interview

  • "I thread each node's in-order predecessor back to it, so I can return without a stack."
  • "Every thread is removed on the way back, so the tree ends unchanged."
  • "It's O(n) time - each edge is walked a constant number of times - and O(1) space."
  • "I'd only use it when O(1) space is required and nothing else reads the tree."

Practice

This skill comes with 10 multiple-choice questions that tell you which misconception a wrong answer reveals and 2 graded problems. Your answers are graded and your mastery is tracked, so you'll know when the skill holds up. Running code and saving progress need a free account.

Practice Morris Threaded Traversal free

Morris Inorder Traversal

HardProCoding problemJava · Python

Given the root of a binary tree, return its inorder traversal using O(1) extra space - no recursion, no explicit stack.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Morris Preorder Traversal

HardProCoding problemJava · Python

Given the root of a binary tree, return its preorder traversal using O(1) extra space - no recursion, no explicit stack.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Practice Morris Threaded Traversal free

No card needed. Lessons, practice questions and easy problems are free forever.

Free plan, no card · 7-day Pro trial · Cancel anytime