Design and Analysis of Algorithms: Lecture 1 - 2
Design and Analysis of Algorithms: Lecture 1 - 2
of Algorithms
(CSE 373)
Lecture 1_2
What is an algorithm?
• A computational procedure that takes
some value, or set of values, as input
produces some value, or set of values, as output
may be specified:
o In English
o As a pseudocode
o As a computer program
English
Pseudocode
key ← A[ j]
For loop body
i = j – 1;
i←j–1 while(i > 0 && A[i] > key){
while i > 0 and A[i] > key A[i+1] = A[i];
do A[i+1] ← A[i] i = i – 1;
While
Loop
body
i←i–1 }//while
A[i+1] ← key A[i+1] = key;
}//for
Indentation/spacing determines where }
the algorithm/loop/if/else-body ends
i j
Insertion Sort Simulation 1 2 3 4 5
key 4 7 4 9 5 1
INSERTION-SORT (A, n) ⊳ A[1 . . n]
for j ← 2 to n i j
1 2 3 4 5
do ⊳ Insert A[ j ] into the sorted subarray A[1..j -1]
⊳ in such a position that A[1..j] becomes sorted key 9 4 7 9 5 1
key ← A[ j]
i←j–1 i j
while i > 0 and A[i] > key 1 2 3 4 5
do A[i+1] ← A[i] key 5 4 7 9 5 1
i←i–1
A[i+1] ← key i j
1 2 3 4 5
key 1 4 5 7 9 1
1 2 3 4 5
1 4 5 7 9
Analysis of Algorithms
• What does it mean to analyze an algorithm?
– To have an estimate about how much time an algorithm may take to
finish, or in other words, to analyze its running time (aka. Time
complexity)
– Sometimes, instead of running time, we are interested in how much
memory/space the algorithm may consume while it runs (space
complexity)
– It enables us to compare between two algorithms
• What do we mean by running time analysis?
– Also referred to as time-complexity analysis
– To determine how running time increases as the size of the problem
increases.
Analysis of Algorithms
– # of elements in a matrix
(how the algorithm performs in all sort of situations.. How the internal
structure of the input)
Example: Counting Operations
How many operations are required?
for (int i = 1; i <= n; i++) {
perform 100 operations; // A
for (int j = 1; j <= n; j++) {
perform 2 operations; // B
}
}
n n n
T (n )
1E+16
1E+14
• In a log-log chart, the 1E+12
1E+10
slope of the line 1E+8
corresponds to the 1E+6
1E+4
growth rate of the 1E+2
function 1E+0
1E+0 1E+2 1E+4 1E+6 1E+8 1E+10
n
Why Choose Leading Term?
• The growth rate is 1E+26
1E+24 Quadratic
Quadratic
not affected by 1E+22
Linear
1E+20
– constant factors or 1E+18 Linear
1E+16
– lower-order terms 1E+14
T (n )
1E+12
• Examples 1E+10
1E+8
– 102n 105 is a 1E+6
linear function 1E+4
1E+2
– 105n2 108n is a 1E+0
quadratic function 1E+0 1E+2 1E+4 1E+6 1E+8 1E+10
n
Why Choose Leading Term?
• Lower order terms contribute lesser to the
overall cost as the input grows larger
• Thus the running times (also called time complexity) of the programs of the
previous slide becomes:
• f(N)= c1N ≈ N*(some constant)
• g(N) = (c1+c2+c3)N+(c1+c2) ≈ N*(some constant)
• Thus both these functions grows linearly with N and as such both have the same
running time (specifically, linear running time). We say that both of them are
O(N) functions, which means that, the running time of each of these algorithms is
a constant multiple of N (we ignore the value of the constant).
• We compare running times of different functions in an asymptotic manner (i.e.,
we check if f(n) > g(n) for very large values of n). That’s why, the task of
computing time complexity (of an algorithm) is also called asymptotic analysis.
Advantage of Asymptotic Analysis
• The definition of time complexity indicates the rate of growth of running
time with the size of input in an asymptotic manner. That’s why, this
definition is independent of machine type, operating system,
programming style, etc. As a result, we can easily compare the
performance of two algorithms without thinking about the platform used
to implement those algorithms.
Remember to THINK BIG when working
• Note:
with asymptotic rates of growth
• Actual execution time is also important because sometimes we see that
one algorithm has lower time complexity but in practice, it performs
worse. This may happen, for e.g., in the following case:
• Algorithm A has time complexity f(n)= cn and
• Algorithm B has time complexity g(n) = dn2
• So theoretically, algorithm A is better (takes less time) than B. But it
turns out that C++ implementation of algorithm B takes less time than
that of A for real inputs. This may happen because
• n is not large practice and
• c >> d
Intuition behind Asymptotic Analysis
• Consider the example of buying elephants and goldfish:
Cost: cost_of_elephants + cost_of_goldfish
Cost ~ cost_of_elephants (approximation)
• The low order terms, as well as constants in a function are
relatively insignificant for large n
f(n) = 6n + 4 ≈ n
g(n) = n4 + 100n2 + 10n + 50 ≈ n4
i.e., we say that n4 + 100n2 + 10n + 50 and n4 have the same rate
of growth. However, f(n) and g(n) have different rate of growths.
The Purpose of Asymptotic Analysis
To estimate how long a program will run.
To estimate the largest input that can reasonably
be given to the program.
To compare the efficiency of different algorithms.
To help focus on the parts of code that are
executed the largest number of times.
To choose an algorithm for an application.
Asymptotic Notations
Examples:
T(n) = 3n2+10nlgn+8 is O(n2), O(n2lgn), O(n3),
O(n4), … O(n2lgn), O(n3), O(n4),
T’(n) = 52n2+3n2lgn+8 is
…
Loose upper
bounds
Asymptotic Notations
• - notation (Big Omega)
Examples:
T(n) = 3n2+10nlgn+8 is Θ(n2)
T’(n) = 52n2+3n2lgn+8 is Θ(n2lgn)
Big O
• Informally, O (g(n)) is the set of all functions with
a smaller or same order of growth as g(n), within
a constant multiple
• If we say f(n) is in O(g(n)), it means that g(n) is an
asymptotic upper bound of f(n)
– Intuitively, it is like f(n) ≤ g(n)
• What is O(n2)?
– The set of all functions that grow slower than or in
the same order as n2
Big-O
f n O g n : { there exist positive constants c and n0 such that
0 f n cg n for all n n0 }
• What does it mean?
– If f(n) = O(n2), then f(n) can be larger than n2 sometimes, but…
• We can choose some constant c and some value n0 such
that for every value of n larger than n0 : f(n) ≤ cn2
• That is, for values larger than n0, f(n) is never more than a
constant multiplier greater than n2
• Or, in other words, f(n) does not grow more than a constant
factor faster than n2
Visualization Big-O
cg(n)
f(n)
n0
Examples
• Show that 30n+8 is O(n).
– Show c,n0: 30n+8 cn, n ≥ n0 .
Value of function
• It isn’t even
less than 31n
everywhere.
• But it is less than
30n+8
n
31n everywhere to O(n)
the right of n=8.
n>n0=8
Increasing n
Big-O Notation
→ Constant time
fA(n)=30n+8
Running time
fB(n)=n2+1
Increasing n
Growth of Functions
Complexity Graphs
log(n)
Complexity Graphs
n log(n)
log(n)
Complexity Graphs
n10 n3
n2
n log(n)
Complexity Graphs (log scale)
3n
nn
n20
2n
n10
1.1n
Types of Time Complexity Analysis
• Worst-case: (usually done)
– Running time on worst possible input
• Best-case: (bogus)
– Running time on best possible input
• To insert the second last element, we need at most (n-2) comparisons and
at most n-2 swaps.
• The number of operations needed to perform insertion sort is therefore:
2×(1+2+⋯+n−2+n−1) = n2+n
So, in the worst case, it runs in O(n2) time.
Insertion Sort: Running Time
Here tj = no. of times the condition of while loop is tested for the current value of j.
How can we simplify T(n)? Hint: compute the value of T(n) in the best/worst case
Insertion Sort: Running Time
Here tj = no. of times the condition of while loop is tested for the current value of j.
In the worst case (when input is reverse-sorted), in each iteration of the for loop, all the j-1
elements need to be right shifted, i.e., tj=(j-1)+1 = j :[1 is added to represent the last test].
Putting this in the above eq., we get: T(n) = An2+Bn+C → O(n2), where A, B, C are constants.
What is T(n) in the best case (when the input numbers are already sorted)?