Data Structures & Algorithms: Industry Edition

Unit 4: Trees

Binary Trees, BST, Traversals, LCA & Kth Element โ€” with real examples from Nykaa, Linux File System & MongoDB.

๐Ÿข Real Projects  |  ๐Ÿ’ป 5 Lab Programs (Python + C)  |  ๐Ÿ“ 25 MCQs  |  ๐ŸŽฏ 3 Interview Questions

Section 1

Industry Hook โ€” The Real-World Problem First

๐Ÿ’„ The Nykaa Problem: 5 Million Products in a Hierarchy

Nykaa, India's largest beauty e-commerce platform, has over 5 million products organized into a deep category hierarchy:

                   Nykaa
              /     |      \
         Beauty   Fashion   Wellness
         /    \       |
   Skincare  Makeup  Ethnic
    /    \
Moisturizer Sunscreen
   /   \
Under โ‚น500  Premium

When a customer searches "moisturizers under โ‚น500," the system must navigate this tree to reach the correct category โ€” that's tree traversal. When an admin adds a new sub-category, they insert a node โ€” that's tree insertion. When Nykaa needs to find the common category between "Sunscreen" and "Moisturizer," it finds "Skincare" โ€” that's the Lowest Common Ancestor (LCA).

The same tree structure powers your computer's file system (C:\ โ†’ Users โ†’ Documents), the Linux kernel's VFS, every database index (MongoDB uses B-Trees), and DOM manipulation in every web browser.

This is exactly the problem trees solve. Let's understand how.

๐Ÿ‡ฎ๐Ÿ‡ณ NykaaLinuxMongoDBChrome DOM
Section 2

Concept Explanation โ€” Theory, Earned

2.1 Binary Trees

Layer 1 โ€” Intuition

A tree is like a family tree โ€” one ancestor (root) at the top, and each person has at most two children (in a binary tree). You can't go "up" without following the parent pointer. A binary tree is the special case where every node has at most 2 children: left and right.

Layer 2 โ€” Visual

Binary Tree Structure
          1           โ† Root (Level 0)
        /   \
       2     3        โ† Level 1
      / \     \
     4   5     6      โ† Level 2 (Leaves: 4, 5, 6)

Terminology:
  Root     = 1 (topmost node, no parent)
  Leaf     = 4, 5, 6 (no children)
  Internal = 1, 2, 3 (at least one child)
  Height   = 2 (longest root-to-leaf path)
  Depth(5) = 2 (edges from root to node 5)

Types of Binary Trees

TypePropertyExample Use
Full Binary TreeEvery node has 0 or 2 childrenExpression trees
Complete Binary TreeAll levels filled except possibly the last (filled left-to-right)Binary heaps
Perfect Binary TreeAll internal nodes have 2 children, all leaves at same levelTheoretical ideal
Extended Binary TreeEvery node has exactly 0 or 2 children (same as Full)Huffman coding trees

Memory Representation

Linked Representation (Most Common)
Each node is a struct/class with 3 fields:
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ left โ”‚ data โ”‚ rightโ”‚
โ””โ”€โ”€โ”ฌโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ฌโ”€โ”€โ”˜
   โ†“              โ†“
 (left child)  (right child)

Sequential (Array) Representation
For node at index i:
  Left child  = 2i + 1
  Right child = 2i + 2
  Parent      = (i - 1) / 2

Index:  0   1   2   3   4   5
Value: [1] [2] [3] [4] [5] [6]

Used for: Binary heaps (complete trees). Wastes space for sparse trees.

2.2 Tree Traversals

The Three Traversal Orders
Tree:       1
          /   \
         2     3
        / \
       4   5

In-order   (Left, Root, Right):  4, 2, 5, 1, 3  โ† Gives SORTED order for BST!
Pre-order  (Root, Left, Right):  1, 2, 4, 5, 3  โ† Used to COPY/SERIALIZE a tree
Post-order (Left, Right, Root):  4, 5, 2, 3, 1  โ† Used to DELETE a tree safely

In-order traversal of a BST always gives sorted output. This is the BST's superpower. If you insert 50, 30, 70, 20, 40, 60, 80 into a BST and do an in-order traversal, you get: 20, 30, 40, 50, 60, 70, 80. Sorted! This is how databases retrieve records "in order" โ€” they traverse a B-Tree in-order.

2.3 Binary Search Tree (BST)

Layer 1 โ€” Intuition

A BST is like a dictionary organized by first letter. If you're looking for "Mango," you open to the middle. "Mango" > "J"? Go right half. "Mango" < "P"? Go left half. Each decision eliminates half the remaining pages โ€” exactly like binary search, but built into the tree structure itself.

Layer 2 โ€” BST Property

BST Property
For EVERY node:
  โ€ข All values in LEFT subtree  < node's value
  โ€ข All values in RIGHT subtree > node's value

        50
       /    \
     30      70       โ† 30 < 50 < 70 โœ“
    /  \    /  \
   20  40  60  80     โ† 20 < 30 < 40 โœ“, 60 < 70 < 80 โœ“

Search for 40:
  50 โ†’ 40 < 50 โ†’ go LEFT
  30 โ†’ 40 > 30 โ†’ go RIGHT
  40 โ†’ FOUND! (3 comparisons for 7 nodes)

Layer 3 โ€” Complexity Table

OperationAverage (Balanced)Worst (Skewed)Space
SearchO(log n)O(n)O(1) iterative / O(h) recursive
InsertO(log n)O(n)Same
DeleteO(log n)O(n)Same
In-order traversalO(n)O(n)O(h) stack
Find Min/MaxO(log n)O(n)O(1)
Real consequence: A balanced BST of Nykaa's 5 million products needs only ~23 comparisons (logโ‚‚ 5M) to find any product. A skewed BST (data inserted in sorted order) degenerates to a linked list and needs 5 million comparisons. This is why databases use self-balancing trees (AVL, Red-Black, B-Trees).

If you insert elements [10, 20, 30, 40, 50] into a BST in that order, what does the tree look like? It becomes a right-skewed linked list! Search becomes O(n). This is why the ORDER of insertion matters, and why self-balancing trees (AVL, Red-Black) exist โ€” they guarantee O(log n) regardless of insertion order.

Section 3

Lab Program Implementations

LAB PROGRAM 1: Create and Traverse Binary Tree Recursively

๐Ÿ“˜ Syllabus: Unit 4 โ€” Binary Tree Traversals๐Ÿข Industry: DOM traversal, file system walk, compiler AST

Python Implementation

Python
class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None


def inorder(root):
    """Left โ†’ Root โ†’ Right. Gives sorted order for BST."""
    if root:
        inorder(root.left)
        print(root.val, end=" ")
        inorder(root.right)

def preorder(root):
    """Root โ†’ Left โ†’ Right. Used to serialize/copy a tree."""
    if root:
        print(root.val, end=" ")
        preorder(root.left)
        preorder(root.right)

def postorder(root):
    """Left โ†’ Right โ†’ Root. Used to delete a tree safely."""
    if root:
        postorder(root.left)
        postorder(root.right)
        print(root.val, end=" ")


# Build tree:     1
#                / \
#               2   3
#              / \
#             4   5
root = TreeNode(1)
root.left = TreeNode(2)
root.right = TreeNode(3)
root.left.left = TreeNode(4)
root.left.right = TreeNode(5)

print("In-order:  ", end=""); inorder(root); print()
print("Pre-order: ", end=""); preorder(root); print()
print("Post-order:", end=""); postorder(root); print()
In-order: 4 2 5 1 3 Pre-order: 1 2 4 5 3 Post-order:4 5 2 3 1

C Implementation

C
#include <stdio.h>
#include <stdlib.h>

struct Node { int data; struct Node *left, *right; };

struct Node* newNode(int val) {
    struct Node* n = (struct Node*)malloc(sizeof(struct Node));
    n->data = val; n->left = n->right = NULL; return n;
}

void inorder(struct Node* r) { if(r){inorder(r->left);printf("%d ",r->data);inorder(r->right);} }
void preorder(struct Node* r) { if(r){printf("%d ",r->data);preorder(r->left);preorder(r->right);} }
void postorder(struct Node* r) { if(r){postorder(r->left);postorder(r->right);printf("%d ",r->data);} }

int main() {
    struct Node* root = newNode(1);
    root->left = newNode(2); root->right = newNode(3);
    root->left->left = newNode(4); root->left->right = newNode(5);
    printf("In:  "); inorder(root); printf("\n");
    printf("Pre: "); preorder(root); printf("\n");
    printf("Post:"); postorder(root); printf("\n");
    return 0;
}

LAB PROGRAM 2: Find All Paths from Root to Leaf

๐Ÿ“˜ Syllabus: Unit 4 โ€” Tree Traversals๐Ÿข Industry: File system path listing, decision tree paths, network routing
Python
def root_to_leaf_paths(root, path, all_paths):
    """Find every path from root to a leaf node.
    Uses backtracking โ€” add current node, recurse, then remove."""
    if not root:
        return
    
    path.append(root.val)                  # Add current node to path
    
    if not root.left and not root.right:   # Leaf โ€” record complete path
        all_paths.append(list(path))
    else:
        root_to_leaf_paths(root.left, path, all_paths)
        root_to_leaf_paths(root.right, path, all_paths)
    
    path.pop()                             # Backtrack โ€” remove current node


# Tree:     1
#          / \
#         2   3
#        / \
#       4   5
paths = []
root_to_leaf_paths(root, [], paths)
for p in paths:
    print(" โ†’ ".join(map(str, p)))
1 โ†’ 2 โ†’ 4 1 โ†’ 2 โ†’ 5 1 โ†’ 3
C
void printPaths(struct Node* root, int path[], int pathLen) {
    if(!root) return;
    path[pathLen++] = root->data;
    if(!root->left && !root->right) {
        for(int i=0;i<pathLen;i++) printf("%d%s",path[i],i<pathLen-1?" -> ":"");
        printf("\n");
    }
    printPaths(root->left, path, pathLen);
    printPaths(root->right, path, pathLen);
}

This uses the backtracking pattern (append โ†’ recurse โ†’ pop). The same approach solves "find all paths in a maze," "all permutations," and "all subsets" โ€” fundamental interview patterns.

LAB PROGRAM 3: Lowest Common Ancestor (LCA) of Two Nodes

๐Ÿ“˜ Syllabus: Unit 4 โ€” Tree Problems๐Ÿข Industry: Nykaa category lookup, Git merge-base, network routing
Python
def find_lca(root, p, q):
    """Find the Lowest Common Ancestor of nodes p and q.
    
    LCA is the deepest node that is an ancestor of both p and q.
    Industry: Nykaa finds the common category between two products.
              Git uses LCA to find the merge-base of two branches.
    
    Algorithm: If both p and q are in the left subtree, LCA is in left.
    If both in right, LCA is in right. If they split, current node IS the LCA.
    """
    if not root or root.val == p or root.val == q:
        return root                       # Base: found p, q, or null
    
    left = find_lca(root.left, p, q)      # Search left subtree
    right = find_lca(root.right, p, q)    # Search right subtree
    
    if left and right:                    # p and q are on different sides
        return root                       # Current node IS the LCA!
    
    return left if left else right       # Both on same side โ€” pass up


# Tree:     1
#          / \
#         2   3
#        / \
#       4   5
result = find_lca(root, 4, 5)
print(f"LCA(4, 5) = {result.val}")      # 2
result = find_lca(root, 4, 3)
print(f"LCA(4, 3) = {result.val}")      # 1
LCA(4, 5) = 2 LCA(4, 3) = 1
C
struct Node* lca(struct Node* root, int p, int q) {
    if(!root || root->data==p || root->data==q) return root;
    struct Node* l = lca(root->left, p, q);
    struct Node* r = lca(root->right, p, q);
    if(l && r) return root;
    return l ? l : r;
}

LAB PROGRAM 4: Insertion and Deletion in BST

๐Ÿ“˜ Syllabus: Unit 4 โ€” BST Operations๐Ÿข Industry: Database index maintenance, in-memory sorted stores
Python
class BST:
    def __init__(self):
        self.root = None

    def insert(self, val):
        """Insert value maintaining BST property. O(log n) avg."""
        self.root = self._insert(self.root, val)

    def _insert(self, node, val):
        if not node:
            return TreeNode(val)           # Base: empty spot found
        if val < node.val:
            node.left = self._insert(node.left, val)   # Go left
        elif val > node.val:
            node.right = self._insert(node.right, val)  # Go right
        # If val == node.val, skip (no duplicates)
        return node

    def delete(self, val):
        """Delete value from BST. Three cases:
        1. Leaf: just remove
        2. One child: replace with child
        3. Two children: replace with in-order successor (min of right subtree)"""
        self.root = self._delete(self.root, val)

    def _delete(self, node, val):
        if not node:
            return node
        if val < node.val:
            node.left = self._delete(node.left, val)
        elif val > node.val:
            node.right = self._delete(node.right, val)
        else:                              # Found the node to delete
            if not node.left:              # Case 1 & 2: no left child
                return node.right
            if not node.right:             # Case 2: no right child
                return node.left
            # Case 3: two children โ€” find in-order successor
            successor = self._find_min(node.right)
            node.val = successor.val         # Copy successor's value
            node.right = self._delete(node.right, successor.val)  # Delete successor
        return node

    def _find_min(self, node):
        while node.left:
            node = node.left
        return node

    def search(self, val):
        return self._search(self.root, val)

    def _search(self, node, val):
        if not node or node.val == val:
            return node
        if val < node.val:
            return self._search(node.left, val)
        return self._search(node.right, val)

    def inorder(self):
        result = []
        self._inorder(self.root, result)
        return result

    def _inorder(self, node, result):
        if node:
            self._inorder(node.left, result)
            result.append(node.val)
            self._inorder(node.right, result)


# === Driver ===
bst = BST()
for v in [50, 30, 70, 20, 40, 60, 80]:
    bst.insert(v)

print("In-order:", bst.inorder())
print("Search 40:", "Found" if bst.search(40) else "Not found")
bst.delete(50)
print("After deleting 50:", bst.inorder())
In-order: [20, 30, 40, 50, 60, 70, 80] Search 40: Found After deleting 50: [20, 30, 40, 60, 70, 80]

C Implementation

C
struct Node* bstInsert(struct Node* root, int val) {
    if(!root) return newNode(val);
    if(val < root->data) root->left = bstInsert(root->left, val);
    else if(val > root->data) root->right = bstInsert(root->right, val);
    return root;
}

struct Node* findMin(struct Node* n) { while(n->left) n=n->left; return n; }

struct Node* bstDelete(struct Node* root, int val) {
    if(!root) return root;
    if(val < root->data) root->left = bstDelete(root->left, val);
    else if(val > root->data) root->right = bstDelete(root->right, val);
    else {
        if(!root->left) { struct Node* t=root->right; free(root); return t; }
        if(!root->right) { struct Node* t=root->left; free(root); return t; }
        struct Node* s = findMin(root->right);
        root->data = s->data;
        root->right = bstDelete(root->right, s->data);
    }
    return root;
}
  1. Deleting a node with two children incorrectly: Students often try to just remove the node. You must replace it with its in-order successor (or predecessor) to maintain the BST property.
  2. Memory leak in C: When deleting a leaf, you must free() it. Forgetting causes leaks in long-running database indexes.
  3. Not returning the modified subtree: In recursive insert/delete, you must return node to reconnect the tree. A common bug is _insert(node.left, val) without node.left =.

LAB PROGRAM 5: Find Kth Smallest and Kth Largest Element in BST

๐Ÿ“˜ Syllabus: Unit 4 โ€” BST Applications๐Ÿข Industry: "Top K products," "Kth rank student," leaderboard systems
Python
def kth_smallest(root, k):
    """In-order traversal gives sorted order. The k-th element visited
    is the k-th smallest. O(h + k) time, O(h) space.
    
    Industry: "Show the 5th cheapest product" on Nykaa/Flipkart."""
    stack = []
    current = root
    count = 0
    
    while stack or current:
        while current:                    # Go to leftmost node
            stack.append(current)
            current = current.left
        
        current = stack.pop()             # Visit node
        count += 1
        if count == k:
            return current.val            # Found k-th smallest!
        
        current = current.right           # Move to right subtree
    
    return None                          # k > number of nodes


def kth_largest(root, k):
    """Reverse in-order (Right, Root, Left) gives descending order.
    The k-th element visited is the k-th largest."""
    stack = []
    current = root
    count = 0
    
    while stack or current:
        while current:                    # Go to rightmost node
            stack.append(current)
            current = current.right
        
        current = stack.pop()
        count += 1
        if count == k:
            return current.val
        
        current = current.left
    
    return None


# BST: [20, 30, 40, 50, 60, 70, 80]
print(f"3rd smallest: {kth_smallest(bst.root, 3)}")
print(f"2nd largest:  {kth_largest(bst.root, 2)}")
3rd smallest: 40 2nd largest: 70

This iterative in-order approach using an explicit stack is the Morris Traversal alternative. It's preferred in interviews because it avoids the recursion limit. The key insight: in-order traversal of a BST = sorted order. So "Kth smallest" is simply "visit K nodes in-order." Time: O(H + K) where H = height.

Section 4

Industry Case Studies

Case Study 1: Nykaa โ€” Product Category Hierarchy

๐Ÿข CompanyNykaa (๐Ÿ‡ฎ๐Ÿ‡ณ India's leading beauty platform โ€” 5M+ products)
โš™๏ธ SystemProduct Category Tree & Navigation Engine
๐Ÿ”ด Problem5 million products in a hierarchy 7 levels deep. Users browse categories (tree traversal), search by category (subtree search), and the system recommends related products (LCA-based similarity).
๐ŸŸข DSA UsedN-ary tree for category hierarchy. Pre-order traversal generates breadcrumb navigation. LCA finds common categories for "similar products." In-order traversal of price BST powers "sort by price."
๐Ÿ“Š Numbers7-level deep tree with ~20,000 category nodes. Any product reachable in โ‰ค7 hops from root. Category page loads in under 100ms.
โœ… OutcomeSmooth category browsing and instant "You might also like" recommendations based on category proximity (LCA depth).
๐Ÿ’ก Student LessonTrees model hierarchical relationships that arrays and linked lists simply can't. If your data has parent-child relationships, trees are the natural choice.

Case Study 2: MongoDB โ€” B-Tree Indexes

๐Ÿข CompanyMongoDB (Global โ€” used by Adobe, eBay, Cisco)
โš™๏ธ SystemDatabase Index Engine (WiredTiger Storage Engine)
๐Ÿ”ด ProblemDatabases store billions of records on disk. Searching 1 billion records linearly = hours. Need O(log n) search with minimal disk reads (each disk read = 10ms).
๐ŸŸข DSA UsedB-Tree (a generalization of BST). Each node has hundreds of keys (fitting one disk block), so tree height is ~3-4 for billions of records. Search = 3-4 disk reads = 30-40ms.
๐Ÿ“Š NumbersB-Tree with branching factor 500: 500ยณ = 125 million records reachable in 3 reads. BST would need logโ‚‚(125M) = 27 reads.
โœ… OutcomeAny record findable in 3-4 disk reads regardless of database size. This is why indexing makes queries 1000x faster.
๐Ÿ’ก Student LessonBSTs are the foundation; B-Trees are the production version. Understanding BST search, insert, delete is understanding how every database works โ€” just with wider nodes.

Case Study 3: Linux โ€” Virtual File System (VFS) Tree

๐Ÿข CompanyLinux Kernel (Infrastructure)
โš™๏ธ SystemVFS โ€” Unified File System Tree
๐Ÿ”ด ProblemLinux must present ext4, NTFS, FAT32, NFS, tmpfs, and dozens of file system types as a single unified directory tree. Path resolution (/home/user/code/main.py) must be fast.
๐ŸŸข DSA UsedN-ary tree of dentry (directory entry) structures. Each directory is a node whose children are its files and subdirectories. The dentry cache (dcache) keeps recently accessed path components in memory.
๐Ÿ“Š NumbersPath resolution: /home/user/code/main.py = 4 tree traversals. Dcache hit rate: ~99% โ€” most lookups don't touch disk at all.
โœ… OutcomeAny file accessible by traversing at most N levels deep (N = path depth). The tree abstraction hides the complexity of dozens of underlying file system drivers.
๐Ÿ’ก Student LessonEvery ls, cd, and open() call traverses a tree. The file system IS a tree. Your Lab Program 2 (root-to-leaf paths) is literally how find / -name "*.py" works.
Section 5

Chapter Project โ€” "Build It Yourself"

๐Ÿ“ File System Simulator with Folder Hierarchy

Pitch: Build a mini Windows Explorer / Linux terminal that lets you create folders, navigate with cd, list with ls, and find files โ€” all using a tree.

Problem Statement

You are a systems programming intern. Build a file system simulator using an N-ary tree where each node represents a file or directory with name, type (file/dir), and children.

Steps

  1. Step 1 โ€” Tree Node: Each node has name, is_dir, and children[] (list of child nodes). Root = "/".
  2. Step 2 โ€” mkdir: Add a child directory node to the current directory (tree insertion from Lab 4).
  3. Step 3 โ€” cd path: Navigate by following the tree path. cd .. goes to parent (needs parent pointer).
  4. Step 4 โ€” ls: List all children of current node (direct children traversal).
  5. Step 5 โ€” find name: Search entire subtree using pre-order traversal (Lab Program 1).
  6. Step 6 โ€” pwd: Print root-to-current path (Lab Program 2).

Extension Challenges

  • โญ Easy: Add file sizes and compute directory sizes recursively
  • โญโญ Medium: Implement rm -r (recursive delete using post-order traversal)
  • โญโญโญ Hard: Implement cp and mv commands (subtree copy/move)
Section 6

Interview Corner โ€” "Crack It at Google/Amazon"

Q1: Maximum Depth of Binary Tree โญ [University + Interview]

Python
def max_depth(root):
    """Height of tree = max depth of any leaf.
    Base case: empty tree has depth 0.
    Recursive: max(left height, right height) + 1."""
    if not root:
        return 0
    return max(max_depth(root.left), max_depth(root.right)) + 1

Time: O(n), Space: O(h). Visits every node exactly once.

Follow-up: (1) Find minimum depth (shortest root-to-leaf). (2) Check if tree is balanced (left and right heights differ by at most 1).

Q2: Validate BST โญโญ [Amazon + Google]

Python
def is_valid_bst(root, min_val=float('-inf'), max_val=float('inf')):
    """Check if tree satisfies BST property.
    Key insight: each node has a VALID RANGE, not just local comparison.
    Node must be > all ancestors in its left lineage, < all in right."""
    if not root:
        return True
    if root.val <= min_val or root.val >= max_val:
        return False                     # Out of valid range!
    return (is_valid_bst(root.left, min_val, root.val) and
            is_valid_bst(root.right, root.val, max_val))

Students often check only node.left.val < node.val < node.right.val. This misses cases where a deep-left node violates the root's constraint. Example: root=10, root.right=15, root.right.left=6. Locally 6 < 15 is fine, but 6 < 10 violates the BST property (6 should be > 10 since it's in the right subtree of 10).

Q3: Level-Order Traversal (BFS) โญโญ [GATE + Interview]

Python
from collections import deque

def level_order(root):
    """BFS on a tree โ€” visit level by level using a queue."""
    if not root: return []
    result, queue = [], deque([root])
    
    while queue:
        level = []
        for _ in range(len(queue)):
            node = queue.popleft()
            level.append(node.val)
            if node.left: queue.append(node.left)
            if node.right: queue.append(node.right)
        result.append(level)
    
    return result
# Output for our tree: [[1], [2, 3], [4, 5]]

Time: O(n), Space: O(w) where w = max width. Uses a queue โ€” connecting stacks/queues (Unit 3) to trees.

Section 7

MCQ Assessment Bank โ€” 25 Questions

Level 1 โ€” Recall โญ (5 Questions)

Q1

In-order traversal visits nodes in which order?

  1. Root, Left, Right
  2. Left, Root, Right
  3. Left, Right, Root
  4. Right, Root, Left
โœ… (b) Left, Root, Right
๐Ÿ“– In-order: L-Root-R. Pre-order: Root-L-R. Post-order: L-R-Root.
โŒ (a) Pre-order. (c) Post-order. (d) Reverse in-order.
Universityโญ Easy
Q2

The BST property states that for every node:

  1. Left child > right child
  2. All left subtree values < node < all right subtree values
  3. Parent > both children
  4. All nodes are at the same level
โœ… (b)
๐Ÿ“– The BST property applies to the ENTIRE subtree, not just immediate children.
โŒ (a) Reversed. (c) That's a max-heap. (d) That's a perfect tree.
GATEโญ Easy
Q3

A binary tree where every node has 0 or 2 children is called:

  1. Complete binary tree
  2. Full binary tree
  3. Perfect binary tree
  4. Balanced binary tree
โœ… (b) Full binary tree
๐Ÿ“– Full = 0 or 2 children. Complete = all levels filled left-to-right. Perfect = full + all leaves at same level.
โŒ Others have different properties.
Universityโญ Easy
Q4

Maximum number of nodes in a binary tree of height h:

  1. 2h
  2. 2h + 1
  3. 2^(h+1) - 1
  4. hยฒ
โœ… (c) 2^(h+1) - 1
๐Ÿ“– A perfect binary tree of height h has 1 + 2 + 4 + ... + 2^h = 2^(h+1) - 1 nodes. Height 2: 1+2+4 = 7 = 2ยณ-1.
โŒ Others are wrong formulas.
GATEโญ Easy
Q5

In array representation of a binary tree, the left child of node at index i is at:

  1. 2i
  2. 2i + 1
  3. i/2
  4. i + 1
โœ… (b) 2i + 1
๐Ÿ“– For 0-indexed arrays: left = 2i+1, right = 2i+2, parent = (i-1)/2. This is used in binary heaps.
โŒ (a) That's 1-indexed. (c) Parent formula. (d) Just the next element.
GATEโญ Easy

Level 2 โ€” Conceptual โญโญ (6 Questions)

Q6

In-order traversal of a BST always gives:

  1. Random order
  2. Sorted ascending order
  3. Sorted descending order
  4. Level order
โœ… (b) Sorted ascending order
๐Ÿ“– BST property guarantees: left < root < right. In-order (L-Root-R) visits smallest first, then root, then largest subtree. Result: ascending order.
โŒ (c) Reverse in-order gives descending.
GATEโญโญ Medium
Q7

Why does BST search degrade to O(n) when elements are inserted in sorted order?

  1. BSTs can't handle sorted data
  2. The tree becomes skewed (each node has only one child) โ€” effectively a linked list
  3. Sorted data causes memory overflow
  4. Hash collisions occur
โœ… (b)
๐Ÿ“– Inserting [10,20,30,40,50] creates: 10โ†’20โ†’30โ†’40โ†’50 (right-skewed). Height = n instead of log n. Search traverses all n nodes.
โŒ (a) BSTs can handle sorted data, just inefficiently. (c)(d) Unrelated.
Interviewโญโญ Medium
Q8 โš ๏ธ TRAP

To check if a binary tree is a valid BST, it's sufficient to verify that for every node, node.left.val < node.val < node.right.val.

  1. True โ€” this is the BST definition
  2. False โ€” you must check against the entire subtree range, not just immediate children
  3. True โ€” parent-child comparison is enough
  4. False โ€” BST validation is impossible
โœ… (b)
๐Ÿ“– Trap! Consider: root=10, right=15, right.left=6. Locally: 6<15 โœ“. But 6 is in root's RIGHT subtree and 6<10 โ€” BST violation! You must pass min/max bounds through recursion.
โŒ (a)(c) The local check misses ancestor violations.
โš ๏ธ TRAPInterviewโญโญ Medium
Q9

Post-order traversal is used to delete a tree because:

  1. It visits the root first
  2. It processes children before the parent โ€” so you don't lose references to children
  3. It's the fastest traversal
  4. It doesn't use recursion
โœ… (b)
๐Ÿ“– If you delete the root first (pre-order), you lose access to both subtrees. Post-order deletes all children first, then the parent โ€” safe deletion order.
โŒ (a) Pre-order visits root first. (c)(d) Wrong.
Universityโญโญ Medium
Q10

When deleting a BST node with two children, we replace it with its:

  1. Left child
  2. Right child
  3. In-order successor (smallest in right subtree) or in-order predecessor
  4. Parent node
โœ… (c)
๐Ÿ“– The in-order successor is the smallest value greater than the deleted node. It maintains BST property because it's > everything in the left subtree and < everything else in the right subtree.
โŒ (a)(b) Would break BST property. (d) Doesn't maintain structure.
GATEโญโญ Medium
Q11

Level-order traversal of a tree uses which data structure?

  1. Stack
  2. Queue
  3. Array
  4. Heap
โœ… (b) Queue
๐Ÿ“– BFS processes nodes level-by-level. A queue (FIFO) ensures nodes are visited in the order they were discovered โ€” parent's children are visited before grandchildren.
โŒ (a) Stack gives DFS (pre-order/post-order).
GATEโญโญ Medium

Level 3 โ€” Application โญโญ (8 Questions)

Q12

Nykaa's category tree has 5 million products and height 7. Maximum comparisons to find any product's category:

  1. 5,000,000
  2. 7
  3. 23 (logโ‚‚ 5M)
  4. 50
โœ… (b) 7
๐Ÿ“– In a tree of height h, the maximum path from root to any node is h edges = h comparisons. With height 7, at most 7 comparisons regardless of total products.
โŒ (a) Linear search. (c) That's BST search on a balanced tree of 5M nodes, not height 7.
Interviewโญโญ Medium
Q13

Pre-order: 1 2 4 5 3 6. In-order: 4 2 5 1 3 6. The tree is:

  1. 1 is root, 2 is left child, 3 is right child, 4/5 are children of 2, 6 is child of 3
  2. Can't determine
  3. 1 is root, 3 is left, 2 is right
  4. Multiple trees possible
โœ… (a)
๐Ÿ“– Pre-order first element (1) is root. In in-order, elements left of 1 (4,2,5) are left subtree, elements right (3,6) are right subtree. Recurse to build the full tree.
โŒ Pre+In uniquely determine a binary tree.
GATEโญโญ Medium
Q14 โš ๏ธ TRAP

The minimum height of a BST containing n nodes is:

  1. n - 1 (right-skewed)
  2. โŒŠlogโ‚‚ nโŒ‹
  3. logโ‚‚ n + 1
  4. n / 2
โœ… (b) โŒŠlogโ‚‚ nโŒ‹
๐Ÿ“– Trap: (a) is the MAXIMUM height (worst case). The MINIMUM height occurs when the tree is perfectly balanced. A complete binary tree of n nodes has height โŒŠlogโ‚‚ nโŒ‹.
โŒ (a) Maximum height. (c)(d) Wrong formulas.
โš ๏ธ TRAPGATEโญโญ Medium
Q15

To find the Kth smallest in a BST of n nodes, the optimal time is:

  1. O(n) โ€” traverse entire tree
  2. O(h + k) โ€” go to leftmost, then visit k nodes in-order
  3. O(k log n)
  4. O(1)
โœ… (b) O(h + k)
๐Ÿ“– Traverse to the leftmost node (O(h)), then visit k nodes in-order (O(k)). Total: O(h + k). For a balanced tree: O(log n + k).
โŒ (a) Too slow. (d) Can't do constant time without augmented BST.
Interviewโญโญ Medium
Q16

What is the space complexity of recursive in-order traversal?

  1. O(1)
  2. O(n)
  3. O(h) where h is tree height
  4. O(n log n)
โœ… (c) O(h)
๐Ÿ“– The recursion depth equals the tree height. Each call adds a frame to the call stack. For balanced trees: O(log n). For skewed: O(n). Generalized: O(h).
โŒ (a) Recursion uses stack space. (b) Only if skewed.
GATEโญโญ Medium
Q17

LCA of nodes 4 and 5 in the tree (root=1, left=2(children 4,5), right=3) is:

  1. 1
  2. 2
  3. 4
  4. 5
โœ… (b) 2
๐Ÿ“– Node 2 is the deepest node that is an ancestor of both 4 and 5. Node 1 is also a common ancestor but not the LOWEST one.
โŒ (a) Common ancestor but not lowest.
Universityโญโญ Medium
Q18

A BST is used instead of a sorted array when:

  1. Only search is needed
  2. Frequent insertions and deletions along with searches
  3. Data is accessed by index
  4. Data fits in cache
โœ… (b)
๐Ÿ“– Sorted array: O(log n) search but O(n) insert/delete (shifting). BST: O(log n) for all three operations. Use BST when data is dynamic (frequent changes).
โŒ (a) Sorted array is better for search-only. (c) Array is better for index access.
Interviewโญโญ Medium
Q19

Which traversal is used to create a copy of a binary tree?

  1. In-order
  2. Pre-order
  3. Post-order
  4. Level-order
โœ… (b) Pre-order
๐Ÿ“– Pre-order visits root first, then children. To copy: create root first, then recursively copy left and right subtrees. You can't create children before the parent.
โŒ (a)(c) Visit root after children โ€” can't create parent after children.
Universityโญโญ Medium

Level 4 โ€” Analysis โญโญโญ (6 Questions)

Q20

MongoDB's B-Tree index with branching factor 500 needs how many disk reads to search 125 million records?

  1. 27 (logโ‚‚ 125M)
  2. 3 (logโ‚…โ‚€โ‚€ 125M)
  3. 125,000,000
  4. 7
โœ… (b) 3
๐Ÿ“– B-Tree with branching factor b has height โ‰ˆ log_b(n). logโ‚…โ‚€โ‚€(125M) = log(125M)/log(500) โ‰ˆ 8.1/2.7 โ‰ˆ 3. Each level = one disk read. BST would need 27 reads. B-Tree: 9x fewer disk accesses.
โŒ (a) BST height, not B-Tree.
Interviewโญโญโญ Hard
Q21 โš ๏ธ TRAP

A balanced BST always has height exactly logโ‚‚(n).

  1. True
  2. False โ€” it has height โŒŠlogโ‚‚(n)โŒ‹ for complete trees, but different balanced trees (AVL, Red-Black) allow slightly different heights
  3. True โ€” by definition of balanced
  4. False โ€” balanced trees have O(1) height
โœ… (b)
๐Ÿ“– "Balanced" doesn't mean "perfect." An AVL tree guarantees height โ‰ค 1.44ยทlogโ‚‚(n). A Red-Black tree guarantees โ‰ค 2ยทlogโ‚‚(n). Both are O(log n) but not exactly logโ‚‚(n). Only a perfect binary tree has height exactly โŒŠlogโ‚‚(n)โŒ‹.
โŒ The exact height depends on the balancing scheme.
โš ๏ธ TRAPGATEโญโญโญ Hard
Q22

Given only post-order and pre-order traversals, can you uniquely reconstruct the binary tree?

  1. Yes โ€” two traversals are always sufficient
  2. No โ€” you need in-order + one of the others
  3. Yes โ€” but only for BSTs
  4. No โ€” three traversals are needed
โœ… (b)
๐Ÿ“– Pre+Post can't distinguish left-only vs right-only children. Example: pre=[1,2], post=[2,1] โ€” is 2 the left or right child of 1? In-order resolves this ambiguity.
โŒ (a) Pre+Post is ambiguous. (c) BSTs can be reconstructed from pre-order alone.
GATEโญโญโญ Hard
Q23

For an LRU cache, which combination gives O(1) for both get and put?

  1. BST alone
  2. Hash Map + Doubly Linked List
  3. Array + BST
  4. Two stacks
โœ… (b) Hash Map + DLL
๐Ÿ“– Hash map: O(1) lookup. DLL: O(1) move-to-front and remove-from-back. BST gives O(log n) โ€” too slow for cache operations that happen millions of times per second.
โŒ (a) O(log n). (c)(d) Can't achieve O(1) for both.
Interviewโญโญโญ Hard
Q24

A complete binary tree is best stored in:

  1. Linked representation (pointers)
  2. Array representation (no wasted space)
  3. Hash table
  4. Stack
โœ… (b) Array
๐Ÿ“– A complete binary tree has no gaps โ€” every array position is used. Array gives O(1) parent/child access via index formulas. This is why binary heaps use arrays. Sparse trees waste array space.
โŒ (a) Works but uses extra pointer space.
GATEโญโญโญ Hard
Q25

The number of distinct BSTs that can be formed with n distinct keys is:

  1. n!
  2. 2โฟ
  3. Catalan number C(n) = (2n)! / ((n+1)! ร— n!)
  4. nยฒ
โœ… (c) Catalan number
๐Ÿ“– For n=3: C(3) = 5 distinct BSTs. For n=4: C(4) = 14. The Catalan number appears in many combinatorial problems: valid parenthesizations, non-crossing partitions, and polygon triangulations.
โŒ (a) n! is number of permutations, not BSTs. (b)(d) Wrong formulas.
GATEโญโญโญ Hard
Section 8

Chapter Summary

5 Things Every Engineer Must Remember

  • Trees model hierarchy โ€” file systems, org charts, DOM, category trees. If your data has parent-child relationships, trees are the natural structure.
  • In-order traversal of BST = sorted output โ€” this single property powers database range queries, Kth element lookups, and ordered iteration. It's the BST's superpower.
  • BST degenerates to O(n) with sorted input โ€” that's why production systems use self-balancing trees (AVL, Red-Black, B-Trees). Understanding the degradation teaches you why balanced trees exist.
  • LCA has real applications โ€” Git's merge-base, Nykaa's product similarity, network routing's common ancestor. The recursive "split detection" algorithm is elegant and interview-critical.
  • BST deletion with two children is the hardest case โ€” replace with in-order successor. Get this right in code and you've mastered 80% of tree manipulation. Every database index does this.

Master Comparison Table

OperationBST (Balanced)BST (Skewed)Array (Sorted)Linked List
SearchO(log n)O(n)O(log n)O(n)
InsertO(log n)O(n)O(n)O(1)*
DeleteO(log n)O(n)O(n)O(1)*
Min/MaxO(log n)O(n)O(1)O(n)
Sorted traversalO(n)O(n)O(n)O(n log n)โ€ 

*At known position. โ€ Must sort first.

Coming Up Next: Unit 5 โ€” Heaps, Hashing & Graphs

Trees organize data hierarchically. But what if you need the maximum element instantly? Every time Ola gets a ride request, it must find the nearest driver from 500,000 active drivers โ€” in under 5ms. A BST search is O(log n), but a heap gives you the min/max in O(1). And what about instant lookups? When PhonePe processes a UPI payment, it must verify the transaction ID against 100 million daily transactions โ€” in O(1). That's hashing.

In Unit 5, we'll master heaps (HeapSort, priority queues), hash tables (separate chaining, linear probing, double hashing), and graphs (BFS, DFS, Dijkstra's shortest path, Floyd-Warshall). We'll build a campus navigation system using Dijkstra's algorithm and a trending hashtag tracker using heaps. This is the final unit โ€” and the most powerful.