Tree Traversal: Code Templates in 6 Languages
If you have not read the concept guide yet, start there for the intuition and complexity analysis. This page gives you the code you can memorize and adapt during an interview. Every template here runs in
TreeNode Definition
The solutions on this page and on the practice problems page assume this node class, which is the same one LeetCode provides in its editor.
class TreeNode {
constructor(val = 0, left = null, right = null) {
this.val = val;
this.left = left;
this.right = right;
}
}Main Template: Recursive Inorder Traversal
This is the template to memorize first, because every depth-first traversal is this function with one line moved. Recurse left, process the node, recurse right. In a BST the output comes back sorted, which is the property that validation problems build on.
Use this for Binary Tree Inorder Traversal .
function inorderTraversal(root) {
const result = [];
function inorder(node) {
if (!node) return;
// The left subtree must finish before this node
// so that smaller values appear first
inorder(node.left);
result.push(node.val);
inorder(node.right);
}
inorder(root);
return result;
}Code Breakdown
Key Variables
| Variable | Purpose |
|---|---|
node | The subtree currently being processed. Null means the subtree is empty and the recursion stops. |
result | Collects node values in visit order. |
stack | In the iterative version, remembers ancestors whose right subtree is still pending. |
queue | In level-order, holds the next level while the current one is processed. |
levelSize | Snapshot of the queue length taken before a level starts, so levels never merge. |
Visual Mechanism
flowchart TD
A["inorder(node)"] --> B{"node is null?"}
B -->|Yes| R["Return"]
B -->|No| L["inorder(node.left)"]
L --> P["Process node.val"]
P --> RT["inorder(node.right)"]
RT --> D["Return"]
Critical Sections
The base case is the null check at the top. Without it the recursion never stops and the first leaf throws. With it, an empty tree and a single node both work with no special cases.
The order of the three lines is the entire pattern. The left subtree must finish before the node is processed, and the node must be processed before the right subtree starts. For a BST that ordering is what turns the walk into a sorted sequence.
The result list is shared across all calls. Each recursive call appends its node and returns, so the list grows in visit order without any explicit combining step.
Variations
1. Iterative Inorder (Explicit Stack)
Use this when the tree can be deep enough to overflow the call stack. The behavior is identical to the recursive version. The stack plays the role the call stack played, so the traversal order does not change.
function inorderTraversalIterative(root) {
const result = [];
const stack = [];
let current = root;
while (current || stack.length) {
// Push every left child on the way down. The
// stack remembers ancestors whose right subtree
// still needs processing.
while (current) {
stack.push(current);
current = current.left;
}
// The top of the stack is the next node in
// inorder order. Process it and move right.
current = stack.pop();
result.push(current.val);
current = current.right;
}
return result;
}2. Level-Order Traversal (BFS)
Use this when the answer depends on depth. Printing levels, finding shortest paths, and anything else that must see the tree one level at a time all need it. A queue holds the current level, and a size snapshot keeps levels from merging.
Use this for Binary Tree Level Order Traversal .
function levelOrder(root) {
if (!root) return [];
const result = [];
const queue = [root];
while (queue.length) {
// Snapshot the size before the loop. Children
// added during this level must wait for the next.
const levelSize = queue.length;
const currentLevel = [];
for (let i = 0; i < levelSize; i++) {
const node = queue.shift();
currentLevel.push(node.val);
if (node.left) queue.push(node.left);
if (node.right) queue.push(node.right);
}
result.push(currentLevel);
}
return result;
}3. Preorder and Postorder
Both are the recursive skeleton with the process line moved. Preorder processes the node before its children, so the root of every subtree arrives first. That is what serialization and cloning rely on. Postorder processes children first, which is what height and path-sum calculations rely on, because the parent needs both subtree answers before it can compute its own.
function preorderTraversal(root) {
const result = [];
function preorder(node) {
if (!node) return;
// Root before children, so the root of every
// subtree arrives first. Serialization and
// cloning rely on that order.
result.push(node.val);
preorder(node.left);
preorder(node.right);
}
preorder(root);
return result;
}
function postorderTraversal(root) {
const result = [];
function postorder(node) {
if (!node) return;
// Children before root, because the parent can
// only be processed once both subtree answers exist.
postorder(node.left);
postorder(node.right);
result.push(node.val);
}
postorder(root);
return result;
}Now head to the practice problems to apply these templates to real interview questions.