Python · SQL · Web Dev · Java · AI/ML tracks launching soon — your one platform for all of IT
Intermediate+150 XP

Unit 11 — Trees

Hierarchical data structures that look like upside-down trees. The foundation of file systems, HTML pages, databases, and compilers. Built from scratch in C with all four traversals.

90 min March 2026
UNIT 11Prerequisite: Unit 05 — Linked Lists90 min read

Every data structure we have covered so far has been linear — arrays, linked lists, stacks, queues all store items in a straight sequence. Trees are different. They store data in a hierarchy — parent–child relationships where one node can connect to multiple others. This single change opens up an entirely new class of problems and solutions.

In this unit we build binary trees from scratch in C, learn all the vocabulary, implement every traversal, and understand the properties that make trees the backbone of some of the most important systems in computing.

// Section 1

What is a Tree?

A tree is a collection of nodes connected by edges, arranged so that there is exactly one path between any two nodes and no cycles. It looks like a real tree — but drawn upside down with the root at the top and the leaves at the bottom.

🏢 Think of a company org chart

The CEO is at the top. Under the CEO are VPs. Under each VP are managers. Under each manager are engineers. This hierarchy is exactly a tree. The CEO is the root. Engineers with no subordinates are leaves.

CEO
VP1
M1
E1
E2
M2
E3
VP2
M3
Root (CEO) — top of tree, no parent
Internal nodes — have parent and children
Internal nodes
Leaves — no children, bottom of tree
// Section 2

Tree Terminology — Words You Must Know

Trees have a vocabulary that everyone uses — in interviews, textbooks, and code reviews. Learn these terms once. You will use them forever.

TermDefinitionIn the org chart example
RootThe topmost node — has no parentCEO
NodeAny single element in the treeAny person in the chart
EdgeThe connection between a parent and childThe line between CEO and VP
ParentThe node directly above another nodeVP1 is parent of M1
ChildA node directly below another nodeM1 and M2 are children of VP1
LeafA node with no childrenE1, E2, E3, M3
HeightLongest path from root to any leaf (in edges)CEO → VP1 → M1 → E1 = height 3
DepthDistance from root to a specific nodeM1 has depth 2
LevelAll nodes at the same depthVP1 and VP2 are at level 1
SubtreeAny node and all its descendantsVP1 + all below it = a subtree
// Section 3

Binary Tree — At Most Two Children

A binary tree is a tree where every node has at most two children — called the left child and the right child. This constraint makes binary trees the most studied and most useful type of tree in computer science. Binary search trees, heaps, expression trees — all are binary trees.

Full Binary Tree
Every node has either 0 or 2 children. No node has exactly 1 child.
Complete Binary Tree
All levels are fully filled except possibly the last, which fills left to right.
Perfect Binary Tree
All internal nodes have exactly 2 children and all leaves are at the same level.
Degenerate Tree
Every parent has only one child — essentially becomes a linked list. Worst case for BST.
// Section 4

Binary Tree in C — Node Structure

A binary tree node is just like a linked list node — but with two next pointers instead of one. A left pointer and a right pointer. Both are NULL for leaf nodes.

c
#include <stdio.h>
#include <stdlib.h>
struct TreeNode {
int data;
struct TreeNode *left; /* pointer to left child */
struct TreeNode *right; /* pointer to right child */
};
typedef struct TreeNode TreeNode;
/* create a new node with given value */
TreeNode* createNode(int value) {
TreeNode *node = (TreeNode*)malloc(sizeof(TreeNode));
node->data = value;
node->left = NULL; /* no left child yet */
node->right = NULL; /* no right child yet */
return node;
}
int main() {
/* build this tree manually:
1
/ \
2 3
/ \
4 5
*/
TreeNode *root = createNode(1);
root->left = createNode(2);
root->right = createNode(3);
root->left->left = createNode(4);
root->left->right = createNode(5);
/* access nodes */
printf("Root: %d\n", root->data); /* 1 */
printf("Left child: %d\n", root->left->data); /* 2 */
printf("Right child: %d\n", root->right->data); /* 3 */
printf("Left->Left: %d\n", root->left->left->data); /* 4 */
return 0;
}
// How node 2 looks in memory — data + two pointers
left*
→ node(4)
data
2
right*
→ node(5)
Each node = 12 bytes on a 64-bit system: 4 (int) + 4 (padding) + 8 (left ptr) + 8 (right ptr)
// Section 5

Tree Traversals — Four Ways to Visit Every Node

With a linked list, there is only one way to traverse: start at head and follow next. With a tree, you have choices. The order in which you visit nodes produces completely different sequences — each useful for different problems. There are four standard traversals. Three use recursion (DFS), one uses a queue (BFS).

// We will use this tree for all four traversal examples
1
2
4
5
3
6
7
root (1)
internal (2, 3)
leaves (4, 5, 6, 7)
Inorder
Left → Root → Right
4 2 5 1 6 3 7
Use: BST sorted output
Preorder
Root → Left → Right
1 2 4 5 3 6 7
Use: Copy / serialize tree
Postorder
Left → Right → Root
4 5 2 6 7 3 1
Use: Delete tree, evaluate expressions
Level Order
Level by level (BFS)
1 2 3 4 5 6 7
Use: Shortest path, level problems
// Section 6

Inorder Traversal — Left, Root, Right

Inorder visits the left subtree first, then the root, then the right subtree. On a Binary Search Tree, inorder traversal always produces a sorted sequence — this is one of the most important tree properties you will use.

// Tracing inorder on our tree — follow Left → Root → Right at every node
inorder(1) → go left first
inorder(2) → go left first
inorder(4) → no left → print 4 → no right → return
print 2 → go right
inorder(5) → no left → print 5 → no right → return
print 1 → go right
inorder(3) → go left first
inorder(6) → no left → print 6 → no right → return
print 3 → go right
inorder(7) → no left → print 7 → no right → return
Result: 4 2 5 1 6 3 7
c
void inorder(TreeNode *root) {
if (root == NULL) return; /* base case: empty subtree */
inorder(root->left); /* 1. visit left subtree */
printf("%d ", root->data); /* 2. print current node */
inorder(root->right); /* 3. visit right subtree */
}
/* inorder(root) → prints: 4 2 5 1 6 3 7 */
Time:O(n)(every node visited exactly once)
Space:O(h)(h = height, call stack depth)
// Section 7

Preorder Traversal — Root, Left, Right

Preorder visits the root first, then the left subtree, then the right subtree. Because you always process the current node before going deeper, preorder is used to copy or serialize a tree — the output can be used to reconstruct the exact same tree.

c
void preorder(TreeNode *root) {
if (root == NULL) return;
printf("%d ", root->data); /* 1. print current node FIRST */
preorder(root->left); /* 2. visit left subtree */
preorder(root->right); /* 3. visit right subtree */
}
/* preorder(root) → prints: 1 2 4 5 3 6 7 */
💡 Note
Real use of preorder: When you save a file system to disk, the folder structure is written in preorder — the folder itself is saved before its contents. When you load it back, you recreate each folder before adding its children. That is preorder traversal in a real system.
// Section 8

Postorder Traversal — Left, Right, Root

Postorder visits the left subtree, then right subtree, and processes the root last. Because you handle all children before the parent, postorder is the natural order for deleting a tree (free children before freeing parent) and evaluating expression trees (compute sub-expressions before applying the operator).

c
void postorder(TreeNode *root) {
if (root == NULL) return;
postorder(root->left); /* 1. visit left subtree */
postorder(root->right); /* 2. visit right subtree */
printf("%d ", root->data); /* 3. print current node LAST */
}
/* postorder(root) → prints: 4 5 2 6 7 3 1 */
/* deleting a tree safely — must use postorder */
void deleteTree(TreeNode *root) {
if (root == NULL) return;
deleteTree(root->left); /* free children first */
deleteTree(root->right);
free(root); /* then free the parent */
}
// Section 9

Level Order Traversal — BFS with a Queue

Level order visits nodes level by level — all nodes at depth 0 first (root), then all at depth 1, then depth 2, and so on. This is Breadth-First Search (BFS) on a tree. Unlike the other three traversals which use recursion and the call stack, level order needs an explicit queue to track which nodes to visit next.

// Visit level by level — breadth first
Level 0
1
→ print: 1
Level 1
2
3
→ print: 2 3
Level 2
4
5
6
7
→ print: 4 5 6 7
Full output: 1 2 3 4 5 6 7
c
#include <stdio.h>
#include <stdlib.h>
/* simple queue using array for level order */
#define QMAX 100
void levelOrder(TreeNode *root) {
if (root == NULL) return;
TreeNode *queue[QMAX];
int front = 0, rear = 0;
queue[rear++] = root; /* enqueue root */
while (front < rear) {
TreeNode *current = queue[front++]; /* dequeue */
printf("%d ", current->data); /* visit current node */
/* enqueue left child if it exists */
if (current->left != NULL) {
queue[rear++] = current->left;
}
/* enqueue right child if it exists */
if (current->right != NULL) {
queue[rear++] = current->right;
}
}
}
/* levelOrder(root) → prints: 1 2 3 4 5 6 7 */
🎯 Pro Tip
Why a queue? When we dequeue a node and process it, we enqueue its children. Children go to the back of the queue — so all siblings at the current level are processed before going deeper. This naturally produces level-by-level order. This exact pattern — queue-based BFS — is used in graph traversal in Unit 15.
// Section 10

Height of a Tree and Counting Nodes

Two of the most common tree problems in interviews. Both use recursion naturally — because the height of a tree depends on the height of its subtrees, and the count of nodes is 1 plus the count of the left subtree plus the right.

c
/* Height = longest path from root to any leaf (measured in edges) */
int height(TreeNode *root) {
if (root == NULL) return -1; /* empty tree has height -1 */
/* (use 0 if measuring in nodes, -1 if measuring in edges) */
int leftHeight = height(root->left);
int rightHeight = height(root->right);
/* height = 1 + the taller of the two subtrees */
int taller = leftHeight > rightHeight ? leftHeight : rightHeight;
return 1 + taller;
}
/* Count = total number of nodes in the tree */
int countNodes(TreeNode *root) {
if (root == NULL) return 0; /* empty tree has 0 nodes */
return 1 + countNodes(root->left) + countNodes(root->right);
/* 1 for current node + all nodes in left + all nodes in right */
}
/* Count only leaf nodes (nodes with no children) */
int countLeaves(TreeNode *root) {
if (root == NULL) return 0;
if (root->left == NULL && root->right == NULL) return 1; /* it is a leaf */
return countLeaves(root->left) + countLeaves(root->right);
}
int main() {
/* build our example tree */
TreeNode *root = createNode(1);
root->left = createNode(2);
root->right = createNode(3);
root->left->left = createNode(4);
root->left->right = createNode(5);
root->right->left = createNode(6);
root->right->right = createNode(7);
printf("Height: %d\n", height(root)); /* 2 */
printf("Total nodes: %d\n", countNodes(root)); /* 7 */
printf("Leaf nodes: %d\n", countLeaves(root)); /* 4 */
return 0;
}
Tracing height(root=1):
height(1) = 1 + max(height(2), height(3))
height(2) = 1 + max(height(4), height(5))
height(4) = 1 + max(-1, -1) = 0
height(5) = 1 + max(-1, -1) = 0
height(2) = 1 + max(0, 0) = 1
height(3) = 1 + max(0, 0) = 1
height(1) = 1 + max(1, 1) = 2 ✓
// Section 11

Trees in the Real World

📁
File systems
Every folder on your computer is a tree node. /home/asil/projects is a path from root to a node. ls -R is a preorder traversal.
🌐
HTML / DOM
Every webpage is a tree. The html tag is the root, head and body are children, and every div, p, span is a node. JavaScript's querySelector walks this tree.
🧮
Expression trees
The expression (3 + 4) × 2 is stored as a tree with × at root, 2 as right child, and + as left child with 3 and 4 as its children. Postorder evaluates it correctly.
🗄️
Database indexes
MySQL and PostgreSQL use B-Trees (a generalisation of binary trees) for indexes. Every time you query with WHERE id = 5, a tree traversal finds it in O(log n).
🔤
Auto-complete and spell check
The Trie data structure (Unit 19) is a tree where each path from root to leaf spells a word. Google's search suggestions use trie-based trees.
// Section 12

Errors You Will Hit

Not checking NULL before accessing node fields
Symptom: Segmentation fault when traversal tries to access root->left->data on a NULL pointer
Fix: Every recursive traversal function must start with: if (root == NULL) return. Never access a field without checking NULL first.
Freeing a parent before freeing children
Symptom: Memory leak — children become unreachable after parent is freed
Fix: Always use postorder to delete a tree — free left subtree, free right subtree, then free the current node.
Confusing height in edges vs height in nodes
Symptom: Height calculations off by 1
Fix: A single node has height 0 (in edges) or height 1 (in nodes). Be consistent. This unit uses edges — base case returns -1 for NULL.
// Quick Reference

All Traversals — Side by Side

TraversalOrderOutput on exampleMethodKey use
InorderLeft → Root → Right4 2 5 1 6 3 7RecursionSorted output from BST
PreorderRoot → Left → Right1 2 4 5 3 6 7RecursionCopy / serialize tree
PostorderLeft → Right → Root4 5 2 6 7 3 1RecursionDelete tree, evaluate expressions
Level OrderLevel by level1 2 3 4 5 6 7Queue (BFS)Shortest path, level problems
// What's Next

You Are Ready for Unit 12

You now understand trees completely — the terminology, the node structure in C, all four traversals with full traces, height, count, and how trees power real systems from file systems to databases.

In Unit 12 we cover the Binary Search Tree (BST) — a binary tree with one powerful rule: every left child is smaller than its parent, every right child is larger. This rule makes search, insert, and delete all run in O(log n) on a balanced tree. The BST is the gateway to understanding every advanced tree structure.

UP NEXT → UNIT 12
Binary Search Tree — O(log n) Everything
Insert, search, delete (3 cases), balanced vs unbalanced — in C.
Coming Soon →

🎯 Key Takeaways

  • A tree stores data in a hierarchy — parent-child relationships with no cycles
  • Binary tree: every node has at most 2 children — left and right
  • Each node in C has: data, *left pointer, *right pointer. Both are NULL for leaf nodes
  • Inorder (L → Root → R): produces sorted output on a BST — most important traversal
  • Preorder (Root → L → R): visits parent before children — used to copy or serialize trees
  • Postorder (L → R → Root): visits children before parent — used to delete trees safely
  • Level order: visits level by level using a queue (BFS) — gives shortest path in unweighted trees
  • Height = longest root-to-leaf path in edges. height(NULL) = -1. height(leaf) = 0
  • All traversals are O(n) time — every node visited exactly once
  • Trees power file systems (preorder), databases (B-trees), HTML (DOM), and compilers
Share

Discussion

0

Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.

Continue with GitHub
Loading...