Data Structures & Algorithms: Industry Edition

Unit 5: Heaps, Hashing & Graphs

HeapSort, Hash Tables, BFS, DFS, Dijkstra's & Floyd-Warshall โ€” with real examples from Ola, PhonePe, Google Maps & IRCTC.

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

Section 1

Industry Hook โ€” The Real-World Problem First

๐Ÿ—บ๏ธ Three Problems That Power India's Digital Infrastructure

Problem 1 โ€” Ola (Heaps): When you book a ride, Ola must find the nearest driver from 500,000 active drivers โ€” in under 5ms. Scanning all 500K drivers linearly is too slow. A min-heap (priority queue) gives the nearest driver in O(1) and updates in O(log n). That's ~19 operations instead of 500,000.

Problem 2 โ€” PhonePe (Hashing): PhonePe processes 7 billion UPI transactions monthly. Every payment must check: "Has this transaction ID been seen before?" Searching 7 billion records linearly = impossible. A hash table answers in O(1) โ€” constant time regardless of table size.

Problem 3 โ€” Google Maps (Graphs): When you search "Delhi to Mumbai" on Google Maps, it explores millions of road segments to find the shortest route. Roads are edges, intersections are vertices โ€” this is a graph. Dijkstra's algorithm finds the shortest path in O((V+E) log V). IRCTC uses the same algorithm to find the best train route with connections.

This is exactly the problem heaps, hashing, and graphs solve. Let's master them all.

๐Ÿ‡ฎ๐Ÿ‡ณ Ola๐Ÿ‡ฎ๐Ÿ‡ณ PhonePeGoogle Maps๐Ÿ‡ฎ๐Ÿ‡ณ IRCTC
Section 2

Concept Explanation โ€” Theory, Earned

2.1 Heaps & HeapSort

Layer 1 โ€” Intuition

A heap is like a VIP hospital queue. The patient with the highest severity (priority) is always treated first. You can add new patients and the most critical one automatically "bubbles up" to the front. A max-heap keeps the maximum at the root; a min-heap keeps the minimum.

Layer 2 โ€” Visual

Max-Heap (parent โ‰ฅ children)
           90
         /    \
       80      70
      /  \    /
    50   60  30

Array: [90, 80, 70, 50, 60, 30]  (level-order)

For index i:
  Parent:      (i-1)/2
  Left child:  2i + 1
  Right child: 2i + 2

Heap Property: arr[parent] โ‰ฅ arr[child] (max-heap)
               arr[parent] โ‰ค arr[child] (min-heap)

Heap Operations

OperationTimeHow
Get Max/MinO(1)Root is always max/min
InsertO(log n)Add at end, bubble UP (sift up)
Extract Max/MinO(log n)Remove root, replace with last, bubble DOWN (heapify)
Build HeapO(n)Bottom-up heapify (not O(n log n)!)
HeapSortO(n log n)Build heap + n extractions

Building a heap from an array is O(n), not O(n log n). This is counter-intuitive โ€” you'd expect n insertions ร— O(log n) each = O(n log n). But bottom-up heapify is smarter: most nodes are near the bottom and need very few swaps. The math proves it converges to O(n). This was proven by Floyd in 1964.

2.2 Hashing & Hash Tables

Layer 1 โ€” Intuition

A hash table is like a library with numbered shelves. Instead of searching every shelf, you compute a shelf number from the book title: "Harry Potter" โ†’ shelf 7. Go directly to shelf 7. Done in O(1).

Layer 2 โ€” Hash Function & Collisions

Hashing Concept
key โ†’ hash_function(key) โ†’ index โ†’ store in array[index]

Example: hash(key) = key % table_size

Insert keys: 25, 37, 42, 55, 73  (table_size = 10)
  25 % 10 = 5  โ†’ slot 5
  37 % 10 = 7  โ†’ slot 7
  42 % 10 = 2  โ†’ slot 2
  55 % 10 = 5  โ†’ COLLISION! Slot 5 already has 25!
  73 % 10 = 3  โ†’ slot 3

Collision Resolution Techniques

TechniqueHow It WorksProsCons
Separate ChainingEach slot holds a linked listSimple, never "full"Extra pointer space, cache unfriendly
Linear ProbingTry next slot: (h+1), (h+2), ...Cache friendlyPrimary clustering
Quadratic ProbingTry (h+1ยฒ), (h+2ยฒ), (h+3ยฒ), ...Less clusteringSecondary clustering, may not find empty slot
Double Hashinghโ‚‚(key) as step: hโ‚ + iยทhโ‚‚Best distributionComplex, needs good hโ‚‚
Real consequence: PhonePe with 7B monthly transactions: hash table lookup = O(1) โ‰ˆ 50 nanoseconds. Linear search = O(n) โ‰ˆ 7 billion ร— 7ns = 49 seconds per lookup. At 2,700 transactions/second, the system would need 49 ร— 2,700 = 132,300 seconds of compute per second. Physically impossible without hashing.

2.3 Graphs โ€” Vertices, Edges, Connections

Layer 1 โ€” Intuition

A graph is a social network. Each person is a vertex, each friendship is an edge. Unlike trees, graphs can have cycles (Aโ†’Bโ†’Cโ†’A), disconnected components, and edges with weights (distance between cities).

Layer 2 โ€” Representations

Example Graph
     A โ€”โ€”(4)โ€”โ€” B
     |         |
    (2)       (3)
     |         |
     C โ€”โ€”(1)โ€”โ€” D

Adjacency Matrix
     A  B  C  D
A  [ 0  4  2  0 ]
B  [ 4  0  0  3 ]
C  [ 2  0  0  1 ]
D  [ 0  3  1  0 ]
Space: O(Vยฒ). Good for dense graphs.

Adjacency List
A โ†’ [(B,4), (C,2)]
B โ†’ [(A,4), (D,3)]
C โ†’ [(A,2), (D,1)]
D โ†’ [(B,3), (C,1)]
Space: O(V+E). Good for sparse graphs.

BFS vs DFS

BFS (Breadth-First)DFS (Depth-First)
Uses a QueueUses a Stack (or recursion)
Visits level by levelGoes deep before backtracking
Finds shortest path (unweighted)Finds all connected components
Google Maps: "How many stops?"Maze solving: "Is there a path?"
Space: O(V)Space: O(V)
Time: O(V+E)Time: O(V+E)

2.4 Shortest Path Algorithms

Dijkstra's Algorithm โ€” Single Source Shortest Path

Find shortest path from A to all vertices:

Graph: A-(4)-B, A-(2)-C, B-(3)-D, C-(1)-D

Step 0: dist = {A:0, B:โˆž, C:โˆž, D:โˆž}     visited = {}
Step 1: Visit A (dist=0)
        Update B: 0+4=4, C: 0+2=2
        dist = {A:0, B:4, C:2, D:โˆž}       visited = {A}
Step 2: Visit C (dist=2, smallest unvisited)
        Update D: 2+1=3
        dist = {A:0, B:4, C:2, D:3}       visited = {A,C}
Step 3: Visit D (dist=3)
        Update B: 3+3=6 > 4, no update
        dist = {A:0, B:4, C:2, D:3}       visited = {A,C,D}
Step 4: Visit B (dist=4)
        dist = {A:0, B:4, C:2, D:3}       visited = {A,C,D,B}

Shortest: Aโ†’B=4, Aโ†’C=2, Aโ†’D=3 (via C!)

Time: O((V+E) log V) with min-heap. Without heap: O(Vยฒ).

Floyd-Warshall โ€” All-Pairs Shortest Path

Finds shortest path between every pair of vertices. Uses dynamic programming: "Can going through vertex k improve the path from i to j?"

Core Idea
for k in all vertices:
    for i in all vertices:
        for j in all vertices:
            dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])

Time: O(Vยณ)   Space: O(Vยฒ)
Used when: You need ALL shortest paths (e.g., IRCTC route planning between ALL station pairs).

Dijkstra's finds shortest paths from ONE source to ALL destinations โ€” O((V+E) log V). Floyd-Warshall finds shortest paths between ALL pairs โ€” O(Vยณ). Google Maps uses Dijkstra (one source: your location). IRCTC precomputes all station-pair distances using Floyd-Warshall. When should you use which?