Analysis of an Algorithm, Asymptotic Notations and Time-Space Trade-off
1. Analysis of an Algorithm
An algorithm is a finite sequence of well-defined steps used to solve a particular problem.
Algorithm analysis is the process of evaluating an algorithm with respect to the resources required for its execution, mainly:
Time – How much computational time the algorithm requires.
Space – How much memory the algorithm requires.
The purpose of algorithm analysis is to determine whether an algorithm is efficient and to compare different algorithms for solving the same problem.
Example
Suppose we want to find an element in an array of n elements.
Linear Search examines elements one by one.
int search(int a[], int n, int key)
{
for (int i = 0; i < n; i++)
{
if (a[i] == key)
return i;
}
return -1;
}If the required element is at the last position, approximately n comparisons may be required.
Therefore, the running time increases with the size of the input.
2. Why Do We Analyze Algorithms?
Two algorithms may produce the same output but require different amounts of time and memory.
For example, consider two algorithms with running times:
and
For small values of n, the difference may not be significant. However, as n becomes large, the second algorithm becomes considerably slower.
Therefore, algorithm analysis helps us:
Select an efficient algorithm.
Compare alternative algorithms.
Predict performance for large inputs.
Identify inefficient portions of a program.
Estimate resource requirements.
Design scalable software.
3. Factors Affecting Algorithm Performance
The performance of an algorithm can depend on several factors:
3.1 Input Size
The amount of input data is represented generally by n.
For example:
Number of elements in an array =
nNumber of vertices in a graph =
VNumber of edges in a graph =
E
As input size increases, execution time may increase.
3.2 Input Characteristics
The arrangement of input data can affect execution time.
For example, in linear search:
Array = [10, 20, 30, 40, 50]Searching for 10 requires only one comparison, whereas searching for 50 requires five comparisons.
3.3 Hardware and Software Environment
Actual execution time also depends on:
Processor speed
Memory
Compiler
Operating system
Programming language implementation
For theoretical algorithm analysis, we generally avoid depending on these machine-specific factors.
4. Types of Algorithm Analysis
Algorithm performance is commonly considered under three cases.
4.1 Best Case
The best case represents the minimum amount of work performed by an algorithm for an input of size n.
Example: Linear Search
If the required element is the first element:
[25, 40, 55, 70, 85]
↑
keyOnly one comparison is required.
Therefore:
4.2 Worst Case
The worst case represents the maximum amount of work performed by an algorithm for an input of size n.
For linear search, the key may be:
at the last position, or
absent from the array.
Approximately n elements may need to be examined.
Therefore:
4.3 Average Case
The average case represents the expected amount of work over possible inputs.
For linear search, if the element is equally likely to occur at any position, the average number of comparisons is approximately:
Although this is approximately n/2, its asymptotic complexity is:
5. Time Complexity
Time complexity describes how the running time of an algorithm grows as the input size increases.
It does not necessarily mean the exact time in seconds.
Instead, it describes the growth rate of the number of fundamental operations.
For example:
for (int i = 0; i < n; i++)
{
printf("%d ", i);
}The loop executes n times.
Therefore:
6. Counting Basic Operations
One way to analyze an algorithm is to count the number of important operations it performs.
Consider:
for (int i = 0; i < n; i++)
{
sum = sum + a[i];
}The addition operation occurs n times.
Thus, the running time grows linearly with n.
Hence:
The objective is generally to determine the order of growth, rather than calculate every machine-level instruction.
7. Common Time Complexities
The most commonly encountered complexity classes are:
| Complexity | Name | Example |
|---|---|---|
O(1) | Constant | Accessing a[5] |
O(log n) | Logarithmic | Binary Search |
O(n) | Linear | Linear Search |
O(n log n) | Linearithmic | Merge Sort |
O(n²) | Quadratic | Bubble Sort |
O(n³) | Cubic | Some matrix algorithms |
O(2ⁿ) | Exponential | Some recursive algorithms |
O(n!) | Factorial | Some brute-force permutation algorithms |
As n becomes very large, algorithms with slower-growing complexity generally become more desirable.
8. Asymptotic Analysis
Asymptotic analysis is a mathematical technique used to describe the growth of an algorithm's resource requirements as the input size approaches a large value.
It allows us to ignore:
Machine-dependent execution time
Constant factors
Lower-order terms
and focus on the dominant growth term.
Example
Suppose:
For large n, the n² term dominates the other terms.
Therefore:
The constants and lower-order terms are ignored when expressing asymptotic growth.
9. Asymptotic Notations
The three fundamental asymptotic notations are:
Big-O notation —
OBig-Omega notation —
ΩBig-Theta notation —
Θ
They provide mathematical bounds on the growth of an algorithm.
10. Big-O Notation — O()
Big-O notation provides an asymptotic upper bound on the growth of a function.
It is commonly used to express the worst-case growth of an algorithm.
If an algorithm takes:
then:
because n² is the dominant term.
Formal Definition
A function f(n) is:
if there exist positive constants c and n₀ such that:
for all:
Example
Since the dominant term is n:
11. Big-Omega Notation — Ω()
Big-Omega notation provides an asymptotic lower bound.
If:
then f(n) grows at least as fast as g(n) asymptotically.
Formal Definition
There exist positive constants c and n₀ such that:
for all:
Example
For:
we can say:
12. Big-Theta Notation — Θ()
Big-Theta notation provides a tight asymptotic bound.
It means that the function grows at the same asymptotic rate as the given function.
If:
then both an upper and lower bound of the same order exist.
Example
Consider:
The dominant term is n².
Therefore:
It is also true that:
and
13. Comparison of O, Ω and Θ
| Notation | Meaning | Type of Bound |
|---|---|---|
O(g(n)) | At most this order of growth | Upper bound |
Ω(g(n)) | At least this order of growth | Lower bound |
Θ(g(n)) | Exactly this order asymptotically | Tight bound |
Easy way to remember
O → Upper bound
Ω → Lower bound
Θ → Tight bound
14. Simplifying Asymptotic Expressions
Consider:
Step 1: Identify the highest-order term.
Step 2: Ignore constant coefficient.
Step 3: Ignore lower-order terms.
Therefore:
Similarly:
and
15. Analysis of Simple C Programs
Example 1: Constant Complexity
int x = a[0];Only one array element is accessed.
Therefore:
Example 2: Linear Complexity
for (int i = 0; i < n; i++)
{
printf("%d ", a[i]);
}The loop executes n times.
Therefore:
Example 3: Quadratic Complexity
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
printf("%d ", a[i][j]);
}
}The outer loop executes n times.
For each outer-loop iteration, the inner loop executes n times.
Therefore:
Hence:
Example 4: Logarithmic Complexity
In binary search, the search space is approximately divided into half after every comparison.
The sequence is:
After k divisions:
Therefore:
Taking logarithm:
Hence binary search has:
16. Space Complexity
Space complexity describes the amount of memory required by an algorithm as a function of input size.
It includes memory required for:
Input data
Variables
Auxiliary data structures
Temporary storage
Function-call stack
Recursion
For example:
int sum = 0;
for (int i = 0; i < n; i++)
{
sum += a[i];
}Apart from the input array, only a few additional variables are used.
Therefore, the auxiliary space is:
17. Auxiliary Space
Auxiliary space refers to the extra memory used by an algorithm apart from the memory required to store the input.
For example, if an algorithm uses an additional array of size n:
If it uses only a few variables:
This distinction is important when analyzing memory-efficient algorithms.
18. Time-Space Trade-off
A time-space trade-off occurs when an algorithm uses more memory to reduce execution time, or uses less memory at the cost of increased execution time.
In other words:
We may sacrifice memory to gain speed, or sacrifice speed to save memory.
19. Example of Time-Space Trade-off
Suppose we frequently need to search for values in a large collection.
Approach 1: Search Every Time
Store the data in an array and perform linear search whenever required.
Extra memory: low
Search time:
O(n)
Approach 2: Use Additional Storage
Create an appropriate indexing or hashing structure.
Additional memory: higher
Search time: potentially much lower, often approximately
O(1)average for a well-designed hash table
Thus, additional memory can be used to reduce computation time.
20. Example: Fibonacci Numbers
Consider the recursive Fibonacci implementation:
int fib(int n)
{
if (n <= 1)
return n;
return fib(n - 1) + fib(n - 2);
}This approach repeatedly calculates the same values.
Its time complexity is exponential:
However, we can store previously calculated Fibonacci values.
fib[0] = 0;
fib[1] = 1;
for (int i = 2; i <= n; i++)
{
fib[i] = fib[i - 1] + fib[i - 2];
}Now:
but:
Thus, additional memory is used to significantly reduce computation time.
This technique is called memoization when previously computed results are stored for reuse.
21. Common Examples of Time-Space Trade-off
| Technique | More Space | Benefit |
|---|---|---|
| Hash Table | Yes | Faster searching |
| Memoization | Yes | Avoids repeated computation |
| Dynamic Programming | Often yes | Reduces repeated subproblems |
| Caching | Yes | Faster access to frequently used data |
| Indexing | Yes | Faster data retrieval |
| Lookup Tables | Yes | Faster computation |
The appropriate trade-off depends on the application.
For example, in a memory-constrained embedded system, saving memory may be more important than achieving the minimum possible execution time. In a high-performance server, faster response may justify additional memory.
22. Time-Space Trade-off vs Space-Time Complexity
These terms should not be confused.
Space Complexity
Measures how much memory an algorithm requires.
Time Complexity
Measures how the execution work grows with input size.
Time-Space Trade-off
Describes the design decision in which one resource is increased to reduce the other.
For example:
or
This is not an absolute rule for every algorithm, but it is a common design principle.
23. Important Complexity Classes
From generally more scalable to less scalable for large n:
This ordering describes the growth rate, not exact execution time for every possible input.
24. Summary
Algorithm analysis is essential for evaluating the efficiency of algorithms. The two primary resources considered are time and space.
Time complexity measures how the computational work grows with input size, while space complexity measures memory requirements.
Asymptotic notations provide mathematical ways of describing algorithm growth:
Big-O (
O) → upper boundBig-Omega (
Ω) → lower boundBig-Theta (
Θ) → tight bound
The time-space trade-off occurs when additional memory is used to reduce computation time or when memory is conserved at the cost of additional computation.
These concepts form the mathematical foundation for comparing and selecting algorithms throughout the study of Data Structures and Algorithms.
No comments:
Post a Comment