A tree traversal method that visits nodes in the order: left child, root, right child. For a Binary Search Tree, this traversal visits nodes in ascending order.
1 2 3 4 5 6 7 8 9 10 11 12 13
{
"status": "starting traversal"
}Overview
In-order traversal visits a binary tree in the order left subtree, then the node itself, then the right subtree. It is a depth-first traversal: it goes as far left as possible before visiting anything, then works its way back up.
Its most important property is that, on a binary search tree, it visits keys in ascending order. That makes it the standard way to print a BST in sorted order, to check whether a tree is a valid BST, or to find the k-th smallest element.
The default tree has 10 at the root, 5 and 15 as its children, and 2, 7, 12 and 18 as leaves. In-order traversal visits 2, 5, 7, 10, 12, 15, 18 — sorted, because the default tree is a valid BST.
Step by step
- If the current node is null, return.
- Recursively traverse the left subtree.
- Visit the current node (record or print its value).
- Recursively traverse the right subtree.
Complexity
| Case | Cost | Why |
|---|---|---|
| Time | O(n) | Every node is visited exactly once. |
| Space (balanced tree) | O(log n) | The recursion stack holds one frame per level. |
| Space (skewed tree) | O(n) | A tree shaped like a linked list is n levels deep. |
When to use it
- Getting the keys of a BST in sorted order.
- Validating a BST: the in-order sequence must be strictly increasing.
- Finding the k-th smallest element, or the in-order successor of a node.
Common mistakes
- Very deep trees can overflow the call stack; an iterative version with an explicit stack avoids this.
- In-order alone cannot reconstruct a tree; you need it together with pre-order or post-order.
- On a tree that is not a BST, the output is not sorted — it simply reflects the tree's shape.
A dry run is the best way to check your understanding of In-order Traversal: follow each row, predict the next one, and compare. The run below takes 60 steps in total. Steps that only re-print loop counters are left out so the decisions stand out. The Line column refers to the line numbers in the code listing above.
- Input
- Binary tree (see the input box above)
- Result
- final_path = [2, 5, 7, 10, 12, 15, 18]
| Step | Line | What happens |
|---|---|---|
| 1 | 1 | status = starting traversal |
| 3 | 4 | from_node = 10, action = traversing left |
| 5 | 4 | from_node = 5, action = traversing left |
| 7 | 4 | from_node = 2, action = traversing left |
| 9 | 3 | node = is null, action = return |
| 10 | 7 | current_node = 2, action = visiting node |
| 12 | 10 | from_node = 2, action = traversing right |
| 14 | 3 | node = is null, action = return |
| 15 | 12 | finished_subtree_at = 2, action = return |
| 16 | 7 | current_node = 5, action = visiting node |
| 18 | 10 | from_node = 5, action = traversing right |
| 20 | 4 | from_node = 7, action = traversing left |
| 22 | 3 | node = is null, action = return |
| 23 | 7 | current_node = 7, action = visiting node |
| 25 | 10 | from_node = 7, action = traversing right |
| 27 | 3 | node = is null, action = return |
| 28 | 12 | finished_subtree_at = 7, action = return |
| 29 | 12 | finished_subtree_at = 5, action = return |
| 30 | 7 | current_node = 10, action = visiting node |
| 32 | 10 | from_node = 10, action = traversing right |
| 34 | 4 | from_node = 15, action = traversing left |
| 36 | 4 | from_node = 12, action = traversing left |
| 38 | 3 | node = is null, action = return |
| 39 | 7 | current_node = 12, action = visiting node |
| 41 | 10 | from_node = 12, action = traversing right |
| 43 | 3 | node = is null, action = return |
| 44 | 12 | finished_subtree_at = 12, action = return |
| 45 | 7 | current_node = 15, action = visiting node |
| 47 | 10 | from_node = 15, action = traversing right |
| 49 | 4 | from_node = 18, action = traversing left |
| 51 | 3 | node = is null, action = return |
| 52 | 7 | current_node = 18, action = visiting node |
| 54 | 10 | from_node = 18, action = traversing right |
| 56 | 3 | node = is null, action = return |
| 57 | 12 | finished_subtree_at = 18, action = return |
| 58 | 12 | finished_subtree_at = 15, action = return |
| 59 | 12 | finished_subtree_at = 10, action = return |
| 60 | 15 | final_path = [2, 5, 7, 10, 12, 15, 18] |