5.3 Counting Steps and Asymptotic Growth
Section 5.2 proved whether an algorithm is correct. Correctness is essential, but it does not tell us whether an algorithm remains practical when its input becomes large.
Suppose two correct search procedures require
basic operations on an input of size . At , the second expression is smaller:
At , the comparison reverses:
To understand scalability, we study how required work grows with input size.
Input size and a cost model
The input size is a number describing how much input an algorithm receives. We usually denote it by .
Examples:
- for an array, may be its number of elements;
- for a graph, size may involve both vertices and edges;
- for an integer, size may mean its number of binary digits rather than its numerical value.
In this section, the meaning of will always be stated.
A cost model chooses which basic operations to count. Examples include comparisons, assignments, arithmetic operations, or array accesses.
The count is a mathematical model, not a stopwatch measurement. Real machines differ in processor speed, language, compiler, and memory behavior. Counting operations lets us compare algorithms independently of those details.
Counting a straight-line procedure
Consider:
x ← a + b
y ← x × 2
return yIf we count arithmetic operations and assignments, a possible model gives:
- one addition;
- one assignment to ;
- one multiplication;
- one assignment to .
The total is , independent of input size. Different reasonable models may count the return or treat an arithmetic assignment as one combined operation. The exact constant changes, but the absence of growth does not.
Counting one loop
Consider:
total ← 0
for i ← 1 to n
total ← total + A[i]
return totalIf we count only executions of the addition in the loop body, the exact count is
If we count one initialization, additions, assignments to , and one return, then
The cost model changes the exact formula, but both formulas grow proportionally to .
Sequential blocks add
If one loop runs times and a later loop runs times, the total number of body executions is
Sequential work adds because the second block runs after the first.
Nested loops multiply
Consider:
for i ← 1 to n
for j ← 1 to n
output (i, j)For each of the values of , the inner loop uses all values of . Therefore the output executes
times.
The iterations correspond to the Cartesian product
connecting this count to Chapter 1.
Not every nested loop is . If the inner loop runs only from through , the count is
This is still quadratic growth, but the exact number is roughly half of .
A loop that repeatedly halves
Consider:
x ← n
while x > 1
x ← floor(x / 2)After iterations, is approximately
The loop stops when this value reaches . Solving
gives
The number of iterations is
for many common loop conventions, up to a small endpoint adjustment. The important fact is logarithmic growth: doubling adds about one more iteration.
Run single, sequential, nested, triangular, and halving loops under a live operation counter. Change , step through highlighted executions, and compare the observed trace against an exact symbolic count you assemble from visual iteration regions.
Best-case and worst-case input behavior
The same input size may produce different costs.
For linear search on an array of length :
- if the target is at index , one comparison is enough;
- if the target is absent or appears only at index , the algorithm makes comparisons.
Therefore:
Whenever we state a complexity, we should identify whether it describes the best case, worst case, or another specified situation. In this course, an unqualified upper-bound analysis usually refers to the worst case.
Why exact formulas are sometimes more detail than we need
Suppose one implementation uses
while another uses
Their exact counts differ. Yet both are dominated by a constant multiple of for large . The quadratic term eventually grows faster than the linear and constant terms.
Asymptotic analysis describes this long-run growth while ignoring constant factors and lower-order terms.
Big-O gives an eventual upper bound
We write
if there exist constants and such that
for every .
The constants and are witnesses. The inequality need not hold for every small input; it must hold from some threshold onward.
Example: proving a quadratic upper bound
Let
For ,
Therefore
Choosing and proves
Big-O is an upper bound, not automatically a tight description. Because for , a linear function also belongs to . To say “grows exactly at this order,” we need matching upper and lower bounds.
Big-Omega gives an eventual lower bound
We write
if there exist constants and such that
for every .
For and ,
so with .
Big-Theta gives a tight growth rate
We write
when both
Equivalently, there are positive constants such that
for every .
Our two bounds prove
Common growth families
From slower to faster, common nonnegative growth rates are:
Here informally means “eventually grows more slowly than.” It is not the partial-order relation from Chapter 4, though both express comparison.
The gaps become dramatic. At :
Constants still matter for real workloads, especially for small inputs. Asymptotic growth answers a different question: what happens as input size continues to increase?
Launch functions with adjustable constant factors into a logarithmic growth race. Move the input-size horizon, inspect crossover points, and fit upper and lower envelopes to distinguish loose Big-O claims from tight Big-Theta classifications.
Chapter bridge
Chapter 5 connected procedures with mathematics. We specified algorithms using pseudocode, proved correctness with invariants and termination measures, counted exact operations, and classified long-run growth.
Chapter 6 develops systematic counting principles. Those tools will let us count choices without listing every outcome—and will also explain why nested loops, search spaces, and combinatorial algorithms can grow so quickly.