Subject Code: SCSA1403 Subject Name: Design and Analysis of Algorithms Unit I Faculty Name: Dr. P. AJITHA
Subject Code: SCSA1403 Subject Name: Design and Analysis of Algorithms Unit I Faculty Name: Dr. P. AJITHA
Flexibility: It must be flexible enough to carry out desired changes with no efforts.
Efficient: The term efficiency is measured in terms of time and space required by an
algorithm to implement. Thus, an algorithm must ensure that it takes little time and
less memory space meeting the acceptable limit of development time.
Independent: An algorithm must be language independent, which means that it
should mainly focus on the input and the procedure required to derive the output
instead of depending upon the language.
Suppose there are 60 students in the class. How will you calculate the number of
absentees in the class?
Algorithm:
The performance of a program is measured based on the amount of computer memory and time
needed to run a program.
The two approaches which are used to measure the performance of the program are:
1. Analytical method called the Performance Analysis.
2. Experimental method called the Performance Measurement.
The Space complexity of a program is defined as the amount of memory it needs to run to
completion.
It is one of the factor which accounts for the performance of the program.
The space complexity can be measured using experimental method, which is done by running
the program and then measuring the actual space occupied by the program during execution.
But this is done very rarely.
We estimate the space complexity of the program before running the program.
The reasons for estimating the space complexity before running the program even for the first
time are:
(1) We should know in advance, whether or not, sufficient memory is present in the computer. If
this is not known and the program is executed directly, there is possibility that the program
may consume more memory than the available during the execution of the program. This
leads to insufficient memory error and the system may crash, leading to severe damages if
that was a critical system.
(2) In Multi user systems, we prefer, the programs of lesser size, because multiple copies of the
program are run when multiple users access the system. Hence if the program occupies less
space during execution, then more number of users can be accommodated.
01/07/2022 SCSA1403 DAA-Unit I 20
SPACE COMPLEXITY
Space complexity is the sum of the following components:
(i) Instruction space:
The program which is written by the user is the source program. When this program is
compiled, a compiled version of the program is generated. For executing the program an executable
version of the program is generated. The space occupied by these three when the program is under
execution, will account for the instruction space.
The instruction space depends on the following factors:
Compiler used – Some compiler generate optimized code which occupies less space.
Compiler options – Optimization options may be set in the compiler options.
Target computer – The executable code produced by the compiler is dependent on the processor
used.
01/07/2022 SCSA1403 DAA-Unit I 21
SPACE COMPLEXITY
Space complexity is the sum of the following components:
(ii) Data space:
The space needed by the constants, simple variables, arrays, structures and other data
structures will account for the data space.
The Data space depends on the following factors:
Structure size – It is the sum of the size of component variables of the structure.
Array size – Total size of the array is the product of the size of the data type and the number of
array locations.
We will be interested in estimating only the variable space because that is the one which varies
according to the user input.
01/07/2022 SCSA1403 DAA-Unit I 24
SPACE COMPLEXITY
int square(int a)
{
return a*a;
}
Totally it requires 4 bytes of memory to complete its execution. And this 4 bytes of memory
is fixed for any input value of 'a'. This space complexity is said to be Constant Space
Complexity.
If any algorithm requires a fixed amount of space for all input values then that space
complexity is said to be Constant Space Complexity
Eg 2:
{
int z = a + b + c;
return(z);
}
Eg.3
#include<stdio.h>
int main()
{
int a = 5, b = 5, c;
c = a + b;
printf("%d", c);
}
Time complexity of the program is defined as the amount of computer time it needs to
run to completion.
The time complexity can be measured, by measuring the time taken by the program
when it is executed. This is an experimental method. But this is done very rarely.
We always try to estimate the time consumed by the program even before it is run for
the first time.
Imagine a classroom of 100 students in which you gave your pen to one person. Now,
you want that pen. Here are some ways to find the pen and what the O order is.
O(n): Going and asking each student individually is O(N).
O(n2): You go and ask the first person of the class, if he has the pen. Also, you ask this person
about other 99 people in the classroom if they have that pen and so on.
O(log n): Now I divide the class into two groups, then ask: “Is it on the left side, or the right
side of the classroom?” Then I take that group and divide it into two and ask again, and so on.
Repeat the process till you are left with one student who has your pen. This is what you mean
by O(log n).
I might need to do the O(n2) search if only one student knows on which
student the pen is hidden.
I’d use the O(n) if one student had the pen and only they knew it.
I’d use the O(log n) search if all the students knew, but would only tell me if I
guessed the right side.
The reasons for estimating the time complexity of the program even before running the
program for the first time are:
(1) We need real time response for many applications. That is a faster execution of the program is
required for many applications. If the time complexity is estimated beforehand, then
modifications can be done to the program to improve the performance before running it.
(2) It is used to specify the upper limit for time of execution for some programs. The purpose of this
is to avoid infinite loops.
The total time taken for the execution of the program is the sum of the compilation time and the
execution time.
(i) Compile time – The time taken for the compilation of the program to produce the intermediate
object code or the compiler version of the program. The compilation time is taken only once as it
is enough if the program is compiled once. If optimized code is to be generated, then the
compilation time will be higher.
(ii) Run time or Execution time - The time taken for the execution of the program. The optimized
code will take less time to get executed.
c -- Compile time
Tp -- Run time or execution time
We will be interested in estimating only the execution time as this is the one which varies according
to the user input.
Time Complexity of algorithm/code is not equal to the actual time required to execute a particular
code but the number of times a statement executes.
We can prove this by using time command.
For example, Write code in C/C++ or any other language to find maximum between N numbers,
where N varies from 10, 100, 1000, 10000.
And compile that code on Linux based operating system (Fedora or Ubuntu) with below command:
You will get surprising results i.e. for N = 10 you may get 0.5ms time and for N = 10, 000 you
may get 0.2 ms time.
Also, you will get different timings on the different machine. So, we can say that actual time
requires to execute code is machine dependent (whether you are using pentium1 or pentiun5) and
also it considers network load if your machine is in LAN/WAN.
Even you will not get the same timings on the same machine for the same code, the reason behind
that the current network load.
Now, the question arises if time complexity is not the actual time require executing the code then
what is it?
The answer is : Instead of measuring actual time required in executing each statement in the
code, we consider how many times each statement execute.
For example: int main()
{
printf("Hello World");
}
Output
Hello World
The answer is : Instead of measuring actual time required in executing each statement in the
code, we consider how many times each statement execute.
For example: int main()
{
printf("Hello World");
}
Output
Hello World
Pseudocode:
Sum(a,b){
return a+b //Takes 2 unit of time(constant) one for arithmetic operation and one for
return.(as per above conventions) cost=2 no of times=1
}
Tsum= 2 = C =O(1)
Table 1:
Pseudocode:
list_Sum(A,n){//A->array and n->number of elements in the array
total =0 // cost=1 no of times=1
for i=0 to n-1 // cost=2 no of times=n+1 (+1 for the end false condition)
sum = sum + A[i] // cost=2 no of times=n
return sum // cost=1 no of times=1
}
Execution times: Not a good measure as execution times are specific to a particular
computer.
A number of statements executed: Not a good measure, since the number of statements
varies with the programming language as well as the style of the individual programmer.
Ideal solution: Let us assume that we express the running time of a given algorithm as a
function of the input size n (i.e., f(n)) and compare these different functions corresponding
to running times. This kind of comparison is independent of machine time, programming
style, etc.
Best Case: In which we analyse the performance of an algorithm for the input, for which the
algorithm takes less time or space.
Worst Case: In which we analyse the performance of an algorithm for the input, for which the
algorithm takes long time or space.
Average Case: In which we analyse the performance of an algorithm for the input, for which the
algorithm takes time or space that lies between best and worst case.
01/07/2022 SCSA1403 DAA-Unit I 49
Growth of Functions and Asymptotic Notation
Big O notation specifically describes worst case scenario. It represents the upper bound running time
complexity of an algorithm. Lets take few examples to understand how we represent the time and
space complexity using Big O notation.
O(1)
Big O notation O(1) represents the complexity of an algorithm that always execute in same time or
space regardless of the input data.
O(1) example
The following step will always execute in same time(or space) regardless of the size of input data.
O(n)
Big O notation O(N) represents the complexity of an algorithm, whose performance will grow
linearly (in direct proportion) to the size of the input data.
O(n) example
The execution time will depend on the size of array. When the size of the array increases, the
execution time will also increase in the same proportion (linearly)
Traversing an array
O(n^2)
Big O notation O(n^2) represents the complexity of an algorithm, whose performance is directly
proportional to the square of the size of the input data.
O(n^2) example
Traversing a 2D array
Omega notation specifically describes best case scenario. It represents the lower bound running time
complexity of an algorithm. So if we represent a complexity of an algorithm in Omega notation, it
means that the algorithm cannot be completed in less time than this, it would at-least take the time
represented by Omega notation or it can take more (when not in best case scenario).
This notation describes both upper bound and lower bound of an algorithm so we can say that it
defines exact asymptotic behaviour. In the real case scenario the algorithm not always run on best and
worst cases, the average running time lies between best and worst and can be represented by the theta
notation.
Examples:
1. f(n) = 3n + 2
3n + 1 ≥ 3n for all n ≥ 0
1. f(n) = 10n2 + 4n + 2
• Definition: f (n) = Θ(g(n)) iff there are three positive constants c1,
c2 and n0 such that
c1|g(n)| ≤ |f (n)| ≤ c2|g(n)| for all n ≥ n0
• If f (n) is nonnegative, we can simplify the last condition to
0 ≤ c1 g(n) ≤ f (n) ≤ c2 g(n) for all n ≥ n0
• We say that “ f (n) is theta of g(n).”
1. If there are two functions f1(n) and f2(n) such that f1(n)=O(g1(n)) and f2(n)=O(g2(n))
then
f1(n)+f2(n)=max(O(g1(n)) ,O(g2(n))).
2. If there are two functions f1(n) and f2(n) such that f1(n)=O(g1(n)) and f2(n)=O(g2(n))
then
f1(n) * f2(n)=O(g1(n)) *(g2(n)).
3. If there exists a function f1 such that f1=f2*c where c is the constant then, f1 and f2 are
equivalent. That means O(f1+f2)=O(f1)=O(f2).
4. If f(n)=O(g(n)) and g(n)=O(h(n)) then f(n)=O(h(n)).
5. In a polynomial the highest power term dominates other terms.
For example if we obtain 3n3+2n2+10 then its time complexity is O(n3).
Any constant value leads to O(1) time complexity. That is if f(n)=c then it Ɛ O(1) time
complexity.
1 0 0 1 2
2 1 2 4 4
4 2 8 16 16
8 3 24 64 256
16 4 64 256 65536
Nlogn nlogn Some instance of input is considered for the list Sorting the elements
of size n. using merge sort or
quick sort.
Exponential 2n When the algorithm has very faster rate of Generating all subsets
growth then this type of efficiency occurs. of n elements.
Linear
for ( i=0 ; i<n ; i++ )
m += i;
Time Complexity O(n)
Quadratic
for ( i=0 ; i<n ; i++ )
for( j=0 ; j<n ; j++ )
sum[i] += entry[i][j];
Time Complexity O(n2)
Cubic
For(i=1;i<=n;i++)
For(j=1;j<=n;j++)
For(k=1;k<=n;k++)
Printf(“AAA”);
Time Complexity is O(n3)
Logarithmic
For(i=1;i<n;i=i*2)
Printf(“AAA”)
Time Complexity O(log n)