Algorithm Analysis

Fundamentals of Algorithms

  • Definition of an Algorithm:     * An algorithm is defined as a specific set of instructions followed to solve a particular problem.     * A single problem can have multiple solutions (different algorithms).     * Algorithms are platform and language independent; they can be implemented using various programming languages (e.g., C++) and run on different platforms.
  • Correctness of Algorithms:     * An algorithm must solve the intended problem correctly.     * Example: In a sorting algorithm, correctness implies the algorithm works even if:         1. The input is already sorted.         2. The input contains repeated elements.
  • Algorithmic Performance Aspects:     * Time: Determined by the execution of instructions. Analysis focuses on how fast an algorithm performs and factors affecting its runtime.     * Space: Determined by the data structures used. Analysis focuses on which data structures are employed and how they affect runtime.     * Course Focus: This study material emphasizes estimating and reducing the time required for an algorithm.

Analysis of Algorithms and Methodology

  • Goal of Analysis: To provide tools to analyze the efficiency of different problem-solving methods independently of specific environments.
  • The Naïve Approach: This involves implementing algorithms (e.g., in C++) and running them to compare time requirements. This approach has significant difficulties:     * Implementation Sensitivity: Comparing running times often compares the quality of the code (programming style) rather than the inherent efficiency of the algorithm.     * Computer Dependency: Running times are affected by the specific hardware used.     * Data Dependency: Results may vary based on the specific data used for the test.
  • Mathematical Techniques: Modern analysis employs techniques that are independent of implementation, computers, or specific data.     1. Count the number of significant operations in a solution to assess efficiency.     2. Express efficiency using growth functions.

Calculation of Execution Time

  • Operation Cost: Each operation in an algorithm has a specific cost (cc) represented in time units.
  • Sequence of Operations: Total cost is the sum of individual costs.     * Example: count = count + 1; (cost c1c_1) followed by sum = sum + count; (cost c2c_2) results in Total Cost = c1+c2c_1 + c_2.
  • Simple If-Statement Analysis:     * if (n < 0) (cost c1c_1, 1 time)     * absval = -n (cost c2c_2, 1 time)     * else absval = n; (cost c3c_3, 1 time)     * Total Cost: Total Costc1+max(c2,c3)\text{Total Cost} \ngtr c_1 + \text{max}(c_2, c_3).
  • Simple Loop Analysis:     * i = 1; (c1c_1, 1 time)     * sum = 0; (c2c_2, 1 time)     * while (i <= n) (c3c_3, n+1n+1 times)     * i = i + 1; (c4c_4, nn times)     * sum = sum + i; (c5c_5, nn times)     * Total Cost Formulation: Total Cost=c1+c2+(n+1)×c3+n×c4+n×c5\text{Total Cost} = c_1 + c_2 + (n+1) \times c_3 + n \times c_4 + n \times c_5.     * Result: The time required is proportional to nn.
  • Nested Loop Analysis:     * i=1; (c1c_1, 1 time)     * sum = 0; (c2c_2, 1 time)     * while (i <= n) (c3c_3, n+1n+1 times)     * j=1; (c4c_4, nn times)     * while (j <= n) (c5c_5, n×(n+1)n \times (n+1) times)     * sum = sum + i; (c6c_6, n×nn \times n times)     * j = j + 1; (c7c_7, n×nn \times n times)     * i = i + 1; (c8c_8, nn times)     * Total Cost Formulation: Total Cost=c1+c2+(n+1)×c3+n×c4+n×(n+1)×c5+n2×c6+n2×c7+n×c8\text{Total Cost} = c_1 + c_2 + (n+1) \times c_3 + n \times c_4 + n \times (n+1) \times c_5 + n^2 \times c_6 + n^2 \times c_7 + n \times c_8.     * Result: The time required is proportional to n2n^2.

General Rules for Estimation

  • Loops: The running time of a loop is at most the running time of the statements inside the loop multiplied by the number of iterations.
  • Nested Loops: The running time is the running time of the statement in the innermost loop multiplied by the product of the sizes of all surrounding loops.
  • Consecutive Statements: Add the running times of each individual consecutive statement.
  • If/Else: The running time is never more than the time of the initial test plus the larger of the running times of the branch statements (S1S_1 and S2S_2).

Algorithm Growth Rates and Big O Notation

  • Problem Size (nn): Time requirements are measured as a function of problem size.     * Example: Number of elements in a list for sorting; number of disks for Towers of Hanoi.
  • Proportional Time: If Algorithm A requires 5×n25 \times n^2 units and Algorithm B requires 7×n7 \times n units, A is proportional to n2n^2 and B is proportional to nn.
  • Growth Rate: The proportional time requirement of an algorithm. Growth rates allow for efficiency comparisons.
  • Big O Notation Definition: Algorithm A is order f(n)f(n)—denoted as O(f(n))O(f(n))—if constants kk and n0n_0 exist such that A requires no more than k×f(n)k \times f(n) time units for a problem size nn0n \ngtr n_0.     * The condition nn0n \ngtr n_0 formalizes the concept of "sufficiently large problems."
  • Example of Order Calculation:     * Requirement: n23×n+10n^2 - 3 \times n + 10 seconds.     * If k=3k = 3 and n0=2n_0 = 2: 3×n2>n23×n+103 \times n^2 > n^2 - 3 \times n + 10 for all n2n \ngtr 2.     * Conclusion: The algorithm is O(n2)O(n^2).

Common Growth Rate Functions

FunctionNameDescription
ccConstantTime is independent of problem size.
log(N)\text{log}(N)LogarithmicTime increases slowly as size increases.
log2N\text{log}^2NLog-squaredHigher order than logarithmic.
NNLinearTime increases directly with problem size.
N log NN \text{ log } NN log NN \text{ log } NIncreases more rapidly than linear.
N2N^2QuadraticTime increases rapidly with problem size.
N3N^3CubicIncreases more rapidly than quadratic.
2N2^NExponentialIncreases too rapidly to be practical for large sizes.

Growth-Rate Function Comparisons

  • Growth comparison for varying nn values:     * When n=10n = 10:         * log2n3\text{log}_2n \ngtr 3         * n10n \ngtr 10         * n×log2n30n \times \text{log}_2n \ngtr 30         * n2100n^2 \ngtr 100         * n31,000n^3 \ngtr 1,000         * 2n1,0002^n \ngtr 1,000     * When n=1,000,000n = 1,000,000:         * log2n19\text{log}_2n \ngtr 19         * n106n \ngtr 10^6         * n×log2n107n \times \text{log}_2n \ngtr 10^7         * n21012n^2 \ngtr 10^{12}         * n31018n^3 \ngtr 10^{18}         * 2n10301,0302^n \ngtr 10^{301,030}
  • Time increase when problem size doubles (from size 8 to size 16 if time at size 8 is 1s):     * O(1)1 secondO(1) \rightarrow 1 \text{ second}     * O(log2n)1×log216log28=43 secondsO(\text{log}_2n) \rightarrow \frac{1 \times \text{log}_216}{\text{log}_28} = \frac{4}{3} \text{ seconds}     * O(n)1×168=2 secondsO(n) \rightarrow \frac{1 \times 16}{8} = 2 \text{ seconds}     * O(n×log2n)1×16×log2168×log28=83 secondsO(n \times \text{log}_2n) \rightarrow \frac{1 \times 16 \times \text{log}_216}{8 \times \text{log}_28} = \frac{8}{3} \text{ seconds}     * O(n2)1×16282=4 secondsO(n^2) \rightarrow \frac{1 \times 16^2}{8^2} = 4 \text{ seconds}     * O(n3)1×16383=8 secondsO(n^3) \rightarrow \frac{1 \times 16^3}{8^3} = 8 \text{ seconds}     * O(2n)1×21628=28=256 secondsO(2^n) \rightarrow \frac{1 \times 2^{16}}{2^8} = 2^8 = 256 \text{ seconds}

Properties of Growth-Rate Functions

  1. Ignore Low-Order Terms: If an algorithm is O(n3+4n2+3n)O(n^3 + 4n^2 + 3n), it is considered O(n3)O(n^3). Only the highest-order term is used.
  2. Ignore Multiplicative Constants: If an algorithm is O(5n3)O(5n^3), it is considered O(n3)O(n^3).
  3. Combination Rules:     * O(f(n))+O(g(n))=O(f(n)+g(n))O(f(n)) + O(g(n)) = O(f(n) + g(n)).     * Example: $$O(n^3