DSA Series · Trees
· Part 2
Tree Traversals
Overview
Traversals visit every node exactly once. The four fundamental orders:
▶ Interactive Traversal Animation
Click a traversal to watch the L‑P‑R tags get crossed out at each node as the algorithm progresses.
Pre-order (Root → Left → Right)
function preorder(node):
if node == null: return visit(node) // process current preorder(node.left) preorder(node.right)
if node == null: return visit(node) // process current preorder(node.left) preorder(node.right)
Visit order: 1, 2, 4, 5, 3, 6, 7
Use case: Copying/serialising a tree, prefix expression evaluation.
▶ Pre-order Recursive Call Stack
Watch the recursion stack grow and shrink as pre-order traverses the tree.
In-order (Left → Root → Right)
function inorder(node):
if node == null: return inorder(node.left) visit(node) // process current inorder(node.right)
if node == null: return inorder(node.left) visit(node) // process current inorder(node.right)
Visit order: 4, 2, 5, 1, 6, 3, 7
Use case: Gives sorted order in a BST. Also for infix expression evaluation.
Post-order (Left → Right → Root)
function postorder(node):
if node == null: return postorder(node.left) postorder(node.right) visit(node) // process current
if node == null: return postorder(node.left) postorder(node.right) visit(node) // process current
Visit order: 4, 5, 2, 6, 7, 3, 1
Use case: Deleting a tree (free children before parent), postfix evaluation, calculating directory sizes.
Level-order (BFS)
function levelOrder(root):
queue = [root] while queue is not empty: node = queue.dequeue() visit(node) if node.left: queue.enqueue(node.left) if node.right: queue.enqueue(node.right)
queue = [root] while queue is not empty: node = queue.dequeue() visit(node) if node.left: queue.enqueue(node.left) if node.right: queue.enqueue(node.right)
Visit order: 1, 2, 3, 4, 5, 6, 7
Use case: Shortest path in unweighted trees, printing level by level.
▶ Level-order BFS Queue Animation
Watch the queue grow and process nodes level by level.
C++ Implementation
#include <queue>
#include <vector>
void preorder(TreeNode* node, std::vector<int>& result) {
if (!node) return;
result.push_back(node->val);
preorder(node->left, result);
preorder(node->right, result);
}
void inorder(TreeNode* node, std::vector<int>& result) {
if (!node) return;
inorder(node->left, result);
result.push_back(node->val);
inorder(node->right, result);
}
void postorder(TreeNode* node, std::vector<int>& result) {
if (!node) return;
postorder(node->left, result);
postorder(node->right, result);
result.push_back(node->val);
}
std::vector<int> levelOrder(TreeNode* root) {
std::vector<int> result;
if (!root) return result;
std::queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
auto* node = q.front(); q.pop();
result.push_back(node->val);
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
return result;
}
Summary
- Pre-order (NLR): root first, then left, then right.
- In-order (LNR): left, root, right. Gives sorted order in a BST.
- Post-order (LRN): left, right, root. Useful for cleanup.
- Level-order (BFS): breadth-first using a queue.