Study Notes: Analysis of Algorithms and Asymptotic Analysis
Introduction to Analysis of Algorithms and Asymptotic Analysis
- An algorithm is a finite set of precise instructions for performing a computation or solving a problem.
- Goal of analysis of algorithms: compare algorithms mainly in terms of running time, but also consider memory requirements, programmer's effort, etc.
- Running time analysis: determine how running time grows as the problem size increases.
Input Size
- Input size definitions vary by problem domain:
- size of an array
- polynomial degree (in algorithms with polynomial expressions)
- # of elements in a matrix
- # of bits in the binary representation of the input
- vertices and edges in a graph
Types of Analysis
- Worst case: provides an upper bound on running time; an absolute guarantee that the algorithm would not run longer, regardless of input.
- Best case: provides a lower bound on running time; the input for which the algorithm runs fastest.
- Average case: provides a prediction about running time; assumes inputs are random.
- Relationships among bounds:
- Lower Bound ≤ Running Time ≤ Upper Bound
How do we compare algorithms?
- We need objective measures. Common considerations:
- Compare execution times: not ideal since times depend on the machine.
- Count the number of statements executed: not ideal since counts vary with language and programmer style.
Ideal Solution
- Express running time as a function of input size n: f(n).
- Compare different functions corresponding to running times.
- This analysis is machine- and language-independent, focusing on growth rates rather than absolute times.
Example: Cost Model (Algorithm 1 and Algorithm 2)
- We can associate a cost with each statement and total cost by counting how many times each statement executes.
- Algorithm 1 and 2 (illustrative cost model):
- arr[0] = 0; cost = c1
- for (i = 0; i < N; i++): cost increment c2 per iteration
- arr[1] = 0; cost increment c1
- arr[i] = 0; cost increment c1
- arr[2] = 0; cost increment c1
- … arr[N-1] = 0; cost increment c1
- Total costs (illustrative):
- Algorithm 1: c1 × N + c2 × (N+1) = (c1 + c2) × N + c2
- Algorithm 2: similar form; total cost shown as (c2 + c1) × N + c2
- Conclusion: Both algorithms are of the same order, O(N).
Example: Algorithm 3 cost
- cost model components: sum = 0; c1
- Nested loops: for i = 0 to N-1; for j = 0 to N-1; sum += arr[i][j];
- Total cost: c1 + c2 × (N+1) + c2 × N × (N+1) + c3 × N^2 = O(N^2)
Asymptotic Analysis
- When comparing two running times f(n) and g(n), we use a rough measure that captures how fast each grows.
- Approach: compare functions in the limit, i.e., asymptotically for large n.
Rate of Growth (intuitive idea)
- Example: buying elephants and goldfish
- Cost = costofelephants + costofgoldfish
- Cost ≈ costofelephants for large n (dominant term)
- For a polynomial example, n^4 + 100n^2 + 10n + 50 ~ n^4 as n → ∞; low-order terms become insignificant for large n.
- Therefore, n^4 + 100n^2 + 10n + 50 and n^4 have the same rate of growth.
Asymptotic Notation
- O-notation (Big-O): asymptotic upper bound
- f(n) = O(g(n)) means: there exist constants c > 0 and n0 such that 0 ≤ f(n) ≤ c·g(n) for all n ≥ n0.
- Ω-notation (Big-Omega): asymptotic lower bound
- f(n) = Ω(g(n)) means: there exist constants c > 0 and n0 such that f(n) ≥ c·g(n) for all n ≥ n0.
- Θ-notation (Big-Theta): asymptotic tight bound
- f(n) = Θ(g(n)) means: f(n) = O(g(n)) and f(n) = Ω(g(n))
Big-O Notation examples
- f(n) = 30n + 8 is O(n)
- f(n) = n^2 + 1 is O(n^2)
- Any O(n^2) function grows faster than any O(n) function.
Visualizing Orders of Growth
- On a graph, as n increases, faster-growing functions eventually dominate slower ones.
- Example: fA(n) = 30n + 8 is eventually dominated by fB(n) = n^2 as n grows large.
More Examples of Orders
- n^4 + 100n^2 + 10n + 50 is O(n^4)
- 10n^3 + 2n^2 is O(n^3)
- n^3 − n^2 is O(n^3)
- Constants are O(1)
- 10 is O(1) and 1273 is O(1)
Back to Our Example (Algorithm Cost)
- Algorithm 1 and Algorithm 2: cost is O(N) (linear)
- Algorithm 3: cost is O(N^2) (quadratic)
Asymptotic Notations (formal definitions)
- O-notation (formal):
- O(g(n)) = { f(n) : there exist positive constants c and n0 such that 0 ≤ f(n) ≤ c g(n) for all n ≥ n0 }
- Big-Omega:
- Ω(g(n)) = { f(n) : there exist positive constants c and n0 such that f(n) ≥ c g(n) for all n ≥ n0 }
- Theta:
- Θ(g(n)) = { f(n) : f(n) ∈ O(g(n)) and f(n) ∈ Ω(g(n)) }
Big-O Visualization (set perspective)
- The set of functions with growth at most that of g(n) is O(g(n)).
- Θ(g(n)) is the intersection of O(g(n)) and Ω(g(n)).
Examples – Two Relationships (quick look)
- n^2 = Ω(n) but not O(n^2) in the sense of strictness; more precise statements follow from definitions.
- n = Θ(n) is trivial; constant factors do not matter in Θ.
- log n and log log n have different growth rates: log log n = o(log n) (and thus O(log n) but not Ω(log n)).
Relationships Between Different Sets
- Subset relations: O(f) ⊆ Θ(f) ⊆ Ω(f) in appropriate contexts, but more precisely:
- Θ(f) ⊆ O(f) and Θ(f) ⊆ Ω(f)
Common Orders of Magnitude (typical growth rates)
- Constant: Θ(1)
- Logarithmic: Θ(log n)
- Linear: Θ(n)
- Linearithmic: Θ(n log n)
- Polynomial: Θ(n^k) for k ≥ 2
- Exponential: Θ(2^n)
- Factorial: Θ(n!)
- (These illustrate a sense of relative growth; exact tables show concrete values for specific n, but growth ordering remains as listed.)
Common Summations (useful in algorithm analysis)
Arithmetic series:
\,\sum_{k=1}^{n} k = \frac{n(n+1)}{2}
Geometric series (finite):
- If x ≠ 1,
\,\sum_{k=0}^{n} x^{k} = \frac{1 - x^{n+1}}{1 - x} - Infinite sum for |x| < 1:
\sum_{k=0}^{\infty} x^{k} = \frac{1}{1 - x}
- If x ≠ 1,
Harmonic series:
\sum{k=1}^{n} \frac{1}{k} = Hn \approx \ln n + \gamma\quad (\gamma\text{ is the Euler–Mascheroni constant})Additional typical approximations:
- \sum_{k=1}^{n} k^p \sim \frac{n^{p+1}}{p+1} \quad\text{for large } n,\text{ when } p > -1
- \sum_{k=1}^{n} \log k \approx n\log n - n (Stirling-type intuition)
Mathematical Induction
- A powerful, rigorous technique to prove a statement S(n) holds for every natural number n.
- Proof structure:
- Basis step: prove S(n) for the initial value (often n = 1).
- Inductive step: assume S(n) true for some n ≥ n0; prove S(n+1) true for all such n.
- Core idea: show that if the statement holds for one case, it holds for the next, propagating truth.
Example (useful induction pattern)
- Statement: Prove that 2^n ≥ n^2 for all n ≥ 4.
- Basis: n = 4 → 2^4 = 16 ≥ 4^2 = 16 (true).
- Inductive step: assume 2^n ≥ n^2 for some n ≥ 4. Then
2^{n+1} = 2\cdot 2^n ≥ 2\cdot n^2.
To conclude 2^{n+1} ≥ (n+1)^2, we require 2n^2 ≥ (n+1)^2, i.e., n^2 ≥ 2n + 1, which holds for n ≥ 3. Since n ≥ 4 in the inductive step, the inequality holds.
- Therefore, by induction, 2^n ≥ n^2 for all n ≥ 4.
Logarithms and properties
- Change of base:
\log_b x = \frac{\ln x}{\ln b} - Basic properties:
- \log(x^k) = k\log x
- \log(xy) = \log x + \log y
- Base changes and relationships among bases yield constant factors, which are absorbed in Θ-notations.
- Common bases: binary (log base 2), natural (ln), and base 10; all differ only by constant factors.
Examples – Relationships (quick exercise guidance)
- If f(n) = log n^2 and g(n) = log n + 5:
- log n^2 = 2 log n, so f(n) = Θ(log n).
- log n + 5 = Θ(log n).
- Therefore, f(n) = Θ(g(n)).
- If f(n) = n and g(n) = log n^2:
- n grows faster than log n^2, so f(n) = Ω(g(n)) (and not O(g(n))).
- If f(n) = log log n and g(n) = log n:
- log log n = o(log n) ⇒ f(n) = O(g(n)) and f(n) ≠ Ω(g(n)).
- If f(n) = n and g(n) = log n:
- f(n) = Ω(g(n)) (and not O(g(n))).
- If f(n) = n log n + n and g(n) = log n:
- f(n) = Ω(g(n)) (grows faster than log n).
- If f(n) = 10 and g(n) = log 10:
- Both are constants; f(n) = Θ(g(n)).
Properties of Asymptotic Notations (summary)
- Theorem: f(n) = Θ(g(n)) ⇔ f(n) = O(g(n)) and f(n) = Ω(g(n)).
- Transitivity:
- If f(n) = Θ(g(n)) and g(n) = Θ(h(n)) ⇒ f(n) = Θ(h(n)).
- Similar transitivity holds for O and Ω with corresponding relations.
- Reflexivity:
- f(n) = Θ(f(n)); f(n) = O(f(n)); f(n) = Ω(f(n)).
- Symmetry:
- f(n) = Θ(g(n)) ⇔ g(n) = Θ(f(n)).
- Transpose symmetry:
- f(n) = O(g(n)) ⇔ g(n) = Ω(f(n)).
Asymptotic Notations in Equations
- If the right-hand side uses Θ(g(n)) as a placeholder for an unknown function, it expresses that the left-hand side equals the right-hand side up to a function in Θ(g(n)).
- Conversely, the left-hand side can be written as Θ(n^2) by choosing an appropriate anonymous function on the right-hand side to make the equality valid.
Common Orders of Magnitude (quick reference)
- Constant: Θ(1)
- Logarithmic: Θ(log n)
- Linear: Θ(n)
- Linearithmic: Θ(n log n)
- Polynomial: Θ(n^k) for k ≥ 2
- Exponential: Θ(2^n)
- Factorial: Θ(n!)
Common Summations (recap)
- Arithmetic series:
\sum_{k=1}^{n} k = \frac{n(n+1)}{2} - Geometric series: finite and infinite forms as above.
- Harmonic series:
\sum{k=1}^{n} \frac{1}{k} = Hn \approx \ln n + \gamma
Summary: Structure of Study Notes
- Key concepts: definitions of input size, cost model, types of analysis, and growth rates.
- Core tools: Big-O, Big-Ω, Big-Θ, and their properties.
- Techniques: rate-of-growth reasoning, limit behavior, and induction.
- Examples: linear vs quadratic time, simple summations, and induction proofs.
- Connections to real-world relevance: choosing efficient algorithms based on input size and growth behavior, not just constant-time measurements.
Note
- The transcript includes a few typographical inconsistencies in the induction example. The essential induction framework is valid: basis, inductive step, and conclusion. A common robust example is proving that a ∈Θ(b) by showing both O- and Ω-bounds via fixed constants after appropriate n0. When practicing, prefer standard, well-checked inequalities (e.g., 2^n ≥ n^2 for n ≥ 4) to avoid edge-case ambiguities.