GeeksforGeeks Hard

Morris Preorder Traversal

Preorder traversal in O(1) space using Morris threading.

treemorristhreading
Open on GeeksforGeeks ↗
02

Intuition

Identical threading to Morris inorder with one change: visit the node when laying the thread (first arrival) instead of when cutting it. Preorder visits parents before left subtrees — first arrival is exactly that moment.

How to spot this pattern

Identical threading machinery to Morris inorder, with the visit moved to the first arrival instead of the second. That single line's position is the entire difference between the two traversals — the same observation that distinguishes recursive preorder from inorder.

03

Approach

1

Same predecessor walk

Find the left subtree's rightmost node; check for an existing thread.

2

Visit on first arrival

No thread → visit cur NOW, lay the thread, descend left. Thread exists → just cut it and go right (already visited).

3

One-line difference

Moving one append between the two branches converts inorder ↔ preorder — worth internalizing.

04

Solution & live demo

1def morris_preorder(root):
2 res, cur = [], root
3 while cur:
4 if not cur.left:
5 res.append(cur.val)
6 cur = cur.right
7 else:
8 pred = cur.left
9 while pred.right and pred.right is not cur:
10 pred = pred.right
11 if not pred.right:
12 res.append(cur.val) # visit on FIRST arrival
13 pred.right = cur
14 cur = cur.left
15 else:
16 pred.right = None
17 cur = cur.right
18 return res
05

Common pitfalls

Visiting on the second arrival

✗ Wrong
else:
    pred.right = None
    res.append(cur.val)
    cur = cur.right
✓ Right
if not pred.right:
    res.append(cur.val)
    pred.right = cur

Emitting when the thread is cut yields inorder. Preorder requires the node before its left subtree, which is the moment the thread is first laid.

Forgetting to visit in the no-left-child branch

✗ Wrong
if not cur.left:
    cur = cur.right
✓ Right
if not cur.left:
    res.append(cur.val)
    cur = cur.right

A node with no left child is never threaded, so this branch is its only chance to be emitted. Skipping it silently drops every such node from the output.

Leaving threads in place

✗ Wrong
else:
    cur = cur.right
✓ Right
else:
    pred.right = None
    cur = cur.right

Even though preorder has already emitted the node by this point, the thread still has to be removed or the tree stays corrupted for every future use. The cut is about restoring the structure, not about output.

06

Edge cases

No left child

Visit and step right — same as inorder here.

Right-only chain

Never threads at all; just walks and visits.

07

Complexity

Time
O(n)
Space
O(1)
Same edge bound as Morris inorder.