Logarithms & Powers of Two

RoadmapsDSA

Overview

A logarithm answers: 'How many times must I divide n by b to reach 1?' log_b(n) is the inverse of exponentiation: if b^k = n, then log_b(n) = k. In algorithms, base 2 is the default because the most common halving operation — dividing a search space in two — produces log2(n) steps.

Logarithms explain why divide-and-conquer algorithms are so fast. Binary search finishes in log2(n) steps because each comparison eliminates half the remaining data. Without understanding logarithms, the leap from O(n) linear search to O(log n) binary search feels like magic rather than mathematics.

Where used: Binary search: log2(n) halvings to narrow a sorted array to one element, Balanced binary tree height: a complete binary tree with n nodes has height log2(n), so insert/search/delete are all O(log n), Merge sort recurrence: splitting n items log2(n) times, doing O(n) work per level, gives O(n log n) total

Why learn this

Aha moment

# How many times can you halve n before reaching 1?
n = 1_000_000_000  # one billion
steps = 0
while n > 1:
    n //= 2
    steps += 1
# steps = 30. One billion shrinks to 1 in only 30 halves.

Prediction: Halving a billion will take hundreds or thousands of steps.

Common guess: It takes roughly 1000 steps to halve a billion down to 1.

It takes only 30 steps. This is because 2^30 is about 10^9. Each halving corresponds to removing one bit from the binary representation. A 30-bit number (which represents up to ~10^9) becomes zero in 30 halvings. This is why binary search on a billion elements needs only 30 comparisons.

Common mistakes

Glossary

divide-and-conquer
A strategy of breaking a large problem into smaller, identical pieces to solve it faster.
bitwise operations
Manipulating data at its most basic level by directly changing ones and zeros.
modular hashing
A technique to wrap large numbers back around into a fixed range using division remainders.

Recall questions

Understanding checks

A sorted array has 1,000,000 elements. Binary search halves the search space each step. How many comparisons does it need in the worst case? What if the array had 1,000,000,000 elements?

log2(10^6) is about 20 comparisons. log2(10^9) is about 30 comparisons. Multiplying the data by 1000x only adds about 10 more steps.

This demonstrates the astonishing practical consequence of logarithmic growth: a thousand-fold increase in data costs only a handful of extra operations. It is the reason binary search and tree-based indices scale to billions of records.

A dynamic array starts with capacity 1 and doubles its capacity each time it fills up. After inserting n elements, how many times has it resized, and why is the total cost of all resizes O(n) despite each individual resize being O(current size)?

It resizes log2(n) times (at capacities 1, 2, 4, 8, ..., up to n). The total copy cost is 1 + 2 + 4 + ... + n = 2n - 1, which is O(n). Even though individual resizes are expensive, they happen so rarely that the total is linear.

This is the geometric series underlying amortized O(1) append: the sum 1 + 2 + 4 + ... + 2^k = 2^(k+1) - 1, which is less than 2n. Powers of two make the series converge, which is why doubling is chosen over, say, adding a fixed amount.

Practice tasks

Compute log2 by hand and connect to algorithm steps

Without a calculator, estimate log2 of each value and state what algorithm analysis it corresponds to: (a) 1024, (b) 10^6, (c) 2^20, (d) 10^18. Use the fact that 2^10 is approximately 10^3.

Continue learning

Previous: Big-O Notation

Previous: Common Complexities

Next: Amortized Analysis

Return to DSA Roadmap