Professional Documents
Culture Documents
Looping
▪ Analysis of Algorithm
▪ The efficient algorithm
▪ Average, Best and Worst case analysis
▪ Asymptotic Notations
▪ Analyzing control statement
▪ Loop invariant and the correctness of the algorithm
▪ Sorting Algorithms and analysis: Bubble sort, Selection sort,
Insertion sort, Shell sort and Heap sort
▪ Sorting in linear time : Bucket sort, Radix sort and Counting sort
▪ Amortized analysis
Introduction
2
Efficiency of Algorithm
The efficiency of an algorithm is a measure of the amount of resources consumed in solving a
problem of size 𝑛.
An algorithm must be analyzed to determine its resource usage.
Two major computational resources are execution time and memory space.
Memory Space requirement can not be compared directly, so the important resource is
computational time required by an algorithm.
To measure the efficiency of an algorithm requires to measure its execution time using any of
the following approaches:
1. Empirical Approach: To run it and measure how much processor time is needed.
2. Theoretical Approach: Mathematically computing how much time is needed as a function of input size.
3
How Analysis is Done?
4
Time Complexity
Time complexity of an algorithm quantifies the amount of time taken by an algorithm to run as
a function of the length of the input.
Running time of an algorithm depends upon,
1. Input Size
2. Nature of Input
Generally time grows with the size of input, for example, sorting 100 numbers will take less
time than sorting of 10,000 numbers.
So, running time of an algorithm is usually measured as a function of input size.
Instead of measuring actual time required in executing each statement in the code, we consider
how many times each statement is executed.
So, in theoretical computation of time complexity, running time is measured in terms of number
of steps/primitive operations performed.
5
Linear Search - Analysis
The required element in the given array can be found at,
Worst Case
Search for 𝟕
𝟐
𝟑 𝟐 𝟗 𝟑 𝟏 𝟖 𝟕
Best Case
Average Case
11
Analysis of Algorithm
12
What is a Good Algorithm?
Efficient
Running time
Space used
Efficiency as a function of input size
The number of bits in an input number
Number of data elements(Numbers and Points)
17
Measuring the Running Time
How should we measure the running time of an algorithm?
Experimental Study
Write a program that implements the algorithm
Run the program with data sets of varying size and composition.
Use a method like System.currentTimeMillis() to get an accurate measure of the actual running time
18
Limitations of Experimental Studies
It is necessary to implement and test the algorithm in order to determine its running time.
Experiments can be done only on a limited set of inputs, and may not be indicative of the
running time on other inputs not included in the experiment.
In order to compare two algorithms, the same hardware and software environments should be
used.
19
Best/Worst/Average Case
For a specific size of input n, investigate running times for different input instances:
20
Best/Worst/Average Case
For inputs of all sizes:
21
Asymptotic Notations
Given two algorithms A1 and A2 for a problem, how do we decide
which one runs faster?
What we need is a platform independent way of comparing algorithms.
Solution: Count the worst-case number of basic operations b(n) for inputs of size n and then
analyse how this function b(n) behaves as n grows. This is known as worst-case analysis.
Observations regarding worst-case analysis:
Usually, the running time grows with the input size n.
Consider two algorithm A1 and A2 for the same problem. A1 has a worst-case running time (100n + 1) and
A2 has a worst-case running time (2n2 + 3n + 1). Which one is better?
▪ A2 runs faster for small inputs (e.g., n = 1, 2)
▪ A1 runs faster for all large inputs (for all n ≥ 49)
We would like to make a statement independent of the input size.
Solution: Asymptotic analysis
▪ We consider the running time for large inputs.
▪ A1 is considered better than A2 since A1 will beat A2 eventually
23
continue..
Solution: Do an asymptotic worst-case analysis.
Observations regarding asymptotic worst-case analysis:
It is difficult to count the number of operations at an extremely fine level and keep track of
these constants.
Asymptotic analysis means that we are interested only in the rate of growth of the running time
function w.r.t. the input size. For example, note that the rates of growth of functions (n2 + 5n +
1) and (n2 + 2n + 5) is determined by the n2 (quadratic) term. The lower order terms are
insignificant. So, we may as well drop them.
The nature of growth rate of functions 2n2 and 5n2 are the same. Both are quadratic functions.
It makes sense to drop these constants too when one is interested in the nature of the growth
functions.
These constants typically depends upon system you are using, such as hardware, compiler etc.
We need a notation to capture the above ideas.
24
Introduction
The theoretical (priori) approach of analyzing an algorithm to measure the efficiency does not
depend on the implementation of the algorithm.
In this approach, the running time of an algorithm is describes as Asymptotic Notations.
Computing the running time of algorithm’s operations in mathematical units of computation
and defining the mathematical formula of its run-time performance is referred to as Asymptotic
Analysis.
An algorithm may not have the same performance for different types of inputs. With the
increase in the input size, the performance will change.
Asymptotic analysis accomplishes the study of change in performance of the algorithm with
the change in the order of the input size.
Using Asymptotic analysis, we can very well define the best case, average case, and worst case
scenario of an algorithm.
25
Asymptotic Notations
Asymptotic notations are mathematical notations used to represent the time complexity of
algorithms for Asymptotic analysis.
Following are the commonly used asymptotic notations to calculate the running time
complexity of an algorithm.
1. Ο Notation
2. Ω Notation
3. θ Notation
This is also known as an algorithm’s growth rate.
Asymptotic Notations are used,
1. To characterize the complexity of an algorithm.
2. To compare the performance of two or more algorithms solving the same problem.
26
1. 𝐎-Notation (Big 𝐎 notation) (Upper Bound)
The notation Ο(𝑛) is the formal way to express the upper bound of an algorithm's running time.
It measures the worst case time complexity or the longest amount of time an algorithm can
possibly take to complete.
For a given function 𝑔(𝑛), we denote by Ο(𝑔(𝑛)) the set of functions,
Ο(g(n)) = {f(n) : there exist positive constants c and n0 such that 0 ≤ f(n) ≤ cg(n) for all n0 ≤ n}
27
Big(𝐎) Notation ▪ 𝑔(𝑛) is an asymptotically upper bound for
𝑓(𝑛).
28
Example
For a function f(n) and g(n) there are positive constants c and n0 such that :
f(n) ≤ c.g(n) for n ≥ n0
29
Example
On the other hand n2 is not O(n) because
there is no c and n0 such that:
n2 ≤ cn for n ≥ n0
30
Simple rule
Drop lower order term and constant factor
31
2. 𝛀-Notation (Omega notation) (Lower Bound)
Big Omega notation (Ω ) is used to define the lower bound of any algorithm or we can say the
best case of any algorithm.
This always indicates the minimum time required for any algorithm for all input values,
therefore the best case of any algorithm.
When a time complexity for any algorithm is represented in the form of big-Ω, it means that the
algorithm will take at least this much time to complete it's execution. It can definitely take
more time than this too.
For a given function 𝑔(𝑛), we denote by Ω(𝑔(𝑛)) the set of functions,
Ω(g(n)) = {f(n):there exist positive constants c and 𝑛0 such that 0 ≤ cg n ≤ f n for all 𝑛0 ≤ n}
32
Big(𝛀) Notation ▪ 𝑔(𝑛) is an asymptotically lower bound for
𝑓(𝑛).
𝒏
𝒏𝟎 𝒇(𝒏) = 𝜴(𝒈(𝒏))
33
3. 𝛉-Notation (Theta notation) (Same order)
The notation θ(n) is the formal way to enclose both the lower bound and the upper bound of an
algorithm's running time.
Since it represents the upper and the lower bound of the running time of an algorithm, it is used
for analyzing the average case complexity of an algorithm.
The time complexity represented by the Big-θ notation is the range within which the actual
running time of the algorithm will be.
So, it defines the exact Asymptotic behavior of an algorithm.
For a given function 𝑔(𝑛), we denote by θ(𝑔(𝑛)) the set of functions,
θ(𝑔(𝑛)) = {𝑓(𝑛) : there exist positive constants c1 , c2 and n0 such that 0 ≤ 𝑐1 𝑔 𝑛 ≤ 𝑓 𝑛 ≤ 𝑐2 𝑔 𝑛 for all 𝑛0 ≤ 𝑛}
34
𝛉-Notation ▪ 𝜃(𝑔(𝑛)) is a set, we can write
𝒄𝟐 . 𝒈(𝒏)
𝑓(𝑛) 𝜖 𝜃(𝑔(𝑛)) to indicate that 𝑓(𝑛) is a
member of 𝜃(𝑔(𝑛)).
Ο(𝑔(𝑛)) = {𝑓(𝑛) : there exist positive constants 𝑐 and 𝑛0 such 𝐟(𝐧) = 𝐎(𝐠(𝐧))
that 𝟎 ≤ 𝒇(𝒏) ≤ 𝒈(𝒏) for all 𝑛0 ≤ 𝑛}
Ω(𝑔(𝑛)) = {𝑓(𝑛) : there exist positive constants 𝑐 and 𝑛0 such that 𝐟 𝐧 = Ω(𝐠(𝐧))
𝟎 ≤ 𝒄𝒈 𝒏 ≤ 𝒇 𝒏 for all 𝑛0 ≤ 𝑛}
θ(𝑔(𝑛)) = {𝑓(𝑛) : there exist positive constants 𝑐1 , 𝑐2 and 𝑛0 such that 𝐟(𝐧) = 𝛉(𝐠(𝐧))
𝟎 ≤ 𝐜𝟏 𝐠 𝐧 ≤ 𝐟 𝐧 ≤ 𝐜𝟐 𝐠 𝐧 for all 𝑛0 ≤ 𝑛}
36
Asymptotic Notations – Examples
Example 1: Example 2:
𝑓(𝑛) = 𝑛2 and 𝑔 𝑛 = 𝑛 𝑓 𝑛 = 𝑛 and 𝑔 𝑛 = 𝑛2
𝑓 𝑛 ≥ 𝑔 𝑛 ⟹ 𝑓 𝑛 = Ω(𝑔(𝑛)) 𝑓 𝑛 ≤ 𝑔 𝑛 ⟹ 𝑓 𝑛 = O(𝑔(𝑛))
37
Asymptotic Notations – Examples
Example 3: 𝑓 𝑛 = 𝑛2 and 𝑔 𝑛 = 2𝑛
𝑓 𝑛 ≤ 𝑔 𝑛 ⟹ 𝑓 𝑛 = O(𝑔(𝑛))
𝒏 𝒇(𝒏) = 𝒏𝟐 𝒈(𝒏) = 𝟐𝒏
1 1 2 𝑓(𝑛) < 𝑔(𝑛)
2 4 4 𝑓(𝑛) = 𝑔(𝑛)
3 9 8 𝑓(𝑛) > 𝑔(𝑛)
4 16 16 𝑓(𝑛) = 𝑔(𝑛)
Here for 𝑛 ≥ 4,
5 25 32 𝑓(𝑛) < 𝑔(𝑛)
𝑓 𝑛 ≤𝑔 𝑛
6 36 64 𝑓(𝑛) < 𝑔(𝑛)
𝑠𝑜, 𝑛0 = 4
7 49 128 𝑓(𝑛) < 𝑔(𝑛)
38
▪ Example 4:
Asymptotic Notations – Examples 𝐟(𝐧) = 𝟑𝟎𝐧 + 𝟖 is in the order of n, or O(n)
𝐠(𝐧) = 𝒏𝟐 + 𝟏 is order n2 , or O(n2 )
𝒇(𝒏) = 𝑶(𝒈(𝒏))
g (n)=n2+1
Value of function →
f(n)=30n+8
▪ In general, any 𝑂(𝑛2 ) function is faster-
growing than any 𝑂(𝑛) function.
Base value 𝑛0
Increasing n →
39
Common Orders of Magnitude
𝒏 𝒍𝒐𝒈 𝒏 𝒏𝒍𝒐𝒈 𝒏 𝒏𝟐 𝒏𝟑 𝟐𝒏 𝒏!
4 2 8 16 64 16 24
16 4 64 256 4096 65536 2.09 x 1013
64 6 384 4096 262144 1.84 × 1019 1.26 x 1029
256 8 2048 65536 16777216 1.15 × 1077 ∞
1024 10 10240 1048576 1.07 × 109 1.79 × 10308 ∞
4096 12 49152 16777216 6.87 × 1010 101233 ∞
40
Asymptotic Notations in Equations
Consider an example of buying elephants and goldfish:
Cost = cost_of_elephants + cost_of_goldfish
Negligible
Cost ≈ cost_of_elephants (approximation)
The low order terms in a function are relatively insignificant for large 𝒏
𝑛4 + 100𝑛2 + 10𝑛 + 50 ≈ 𝑛4
42
Exercises
1. Express the function 𝑛3/1000 − 100𝑛2 − 100𝑛 + 3 in terms of θ notation.
2. Express 20𝑛3 + 10𝑛 log 𝑛 + 5 in terms of O notation.
3. Express 5𝑛 log 𝑛 + 2𝑛 in terms of O notation.
4. Prove or disprove (i) Is 2n+1 = O(2n) (ii) Is 22n = O(2n)
5. Check the correctness for the following equality, 5n3 + 2n = O(n3 )
6. Find θ notation for the following function
a. F(𝑛) = 3 ∗ 2𝑛 + 4𝑛2 + 5𝑛 + 2
7. Find O notation for the following function
a. F(n) = 2n + 6n2 + 3n
b. F(n) = 4n3 + 2n + 3
8. Find Ω notation for the following function
a. F(n) = 4 ∗ 2n + 3n
b. F(n) = 5n3 + n2 + 3n + 2
43
Methods of proving Asymptotic Notations
1) Proof by definition : In this method, we apply the formal definition of the
asymptotic notation, and find out the values of constants c > 0 and n0 > 0, such that the required
notation is proved.
2) Proof by Limit Rules : In this method, we apply certain rules of limit, and then
prove the required notation.
44
Proof by definition
Prove the following statements :
1. n2 + n = O(n2) ≈ O(n3)
According to the formal definition, let f(n) = n2 + n and g(n) = n2
Find the values of constants c > 0 and n0 > 0, such that 0 ≤ f(n) ≤ c g(n), for all n ≥ n0 (condition for Big-O
notation)2
2. n3 + 4n2 = Ω(n2) ≈ Ω(n)
According to the formal definition, let f(n) = n3 + 4n2 and g(n) = n2
Find the values of constants c > 0 and n0 > 0, such that 0 ≤ c g(n) ≤ f(n), for all n ≥ n0 (condition for Big-Ω
notation)
3. n2 + n = Θ(n2)
According to the formal definition, let f(n) = n2 + n and g(n) = n2
Find the values of constants c1 > 0, c2 > 0, and n0 > 0, such that 0 ≤ c1 g(n) ≤ f(n) ≤ c2 g(n), for all n ≥ n0
(condition for Θ notation)
45
Proof by Limit Rules
If f(n) and g(n) are asymptotically increasing functions, then the following rules hold true:
47
Asymptotic Notations and their meanings
1)Big-O notation : Represents asymptotic upper bound
Ex: The running time T(n) = 2n2 + 4n + 5 can be expressed as O(n2) or O(n3) or O(n4).
4)Little-o notation : Represents upper bound that is not asymptotically tight (strict upper bound)
Ex: The running time T(n) = 2n2 + 4n + 5 can be expressed as o(n3) or o(n2.1), but not as o(n2).
5)Little-ѡ notation : Represents lower bound that is not asymptotically tight (strict lower bound)
Ex: The running time T(n) = 2n2 + 4n + 5 can be expressed as ѡ(n) or ѡ(n1.99), but not as ѡ(n2).
Math You Need to Review
Properties of logarithms:
Properties of exponentials:
Geometric progression:
Arithmetic progression:
49
Analyzing Control Statements
For Loop
# Input : int A[n], array of n integers
# Output : Sum of all numbers in array A
51
Running Time of Algorithm
The time complexity of the algorithm is : 𝒇 𝒏 = 𝟐 ∙ 𝒏 + 𝟑
Estimated running time for different values of 𝑛 :
𝒏 = 𝟏𝟎 23 steps
As 𝑛 grows, the number of steps grow in linear proportion to 𝑛 for the given algorithm Sum.
The dominating term in the function of time complexity is 𝒏: As 𝑛 gets large, the +3 becomes
insignificant.
The time is linear in proportion to 𝒏.
52
Analyzing Control Statements
Example 1: Example 3:
𝑠𝑢𝑚 = 𝑎 + 𝑏; 𝐜 𝑓𝑜𝑟 𝑖 = 1 𝑡𝑜 𝑛 𝑑𝑜 𝒄𝟏 𝒏 + 𝟏
▪ Statement is executed once only 𝑓𝑜𝑟 𝑗 = 1 𝑡𝑜 𝑛 𝑑𝑜 𝒄𝟐 𝒏 𝒏 + 𝟏
▪ So, The execution time 𝑇(𝑛) is some 𝑠𝑢𝑚 = 𝑎 + 𝑏; 𝒄 ∗ 𝒏 ∗ 𝒏
constant 𝐜 ≈ 𝑶(𝟏) 𝟑
▪ Analysis
Example 2: 𝑇 𝑛 = 𝑐1 𝑛 + 1 + 𝑐2 𝑛 𝑛 + 1 + 𝑐3 𝑛 𝑛
𝑇(𝑛) = 𝑐1 𝑛 + 𝑐1 + 𝑐2 𝑛2 + 𝑐2 𝑛 + 𝑐3 𝑛2
𝑓𝑜𝑟 𝑖 = 1 𝑡𝑜 𝑛 𝑑𝑜 𝐜𝟏 ∗ 𝒏 + 𝟏 𝑇(𝑛) = 𝑛2(𝑐2 + 𝑐3 ) + 𝑛(𝑐1 + 𝑐2 ) + 𝑐1
𝑠𝑢𝑚 = 𝑎 + 𝑏; 𝑇(𝑛) = 𝑎𝑛2 + 𝑏𝑛 + 𝑐
𝐜𝟐 ∗ 𝒏 𝑻(𝒏) = 𝑶 𝒏𝟐
▪ Total time is denoted as,
𝑻 𝒏 = 𝒄𝟏 𝒏 + 𝒄𝟏 + 𝒄𝟐 𝒏
𝑻(𝒏) = 𝒏(𝒄𝟏 + 𝒄𝟐 ) + 𝒄𝟏 ≈ 𝑶(𝒏)
53
Analyzing Control Statements
Example 4: Example 6:
𝑙 = 0 𝑓𝑜𝑟 𝑗 = 1 𝑡𝑜 𝑛 𝑑𝑜
𝑓𝑜𝑟 𝑖 = 1 𝑡𝑜 𝑛 𝑑𝑜 𝑓𝑜𝑟 𝑘 = 1 𝑡𝑜 𝑗 𝑑𝑜 𝜽 𝒏𝟐
𝑓𝑜𝑟 𝑗 = 1 𝑡𝑜 𝑖 𝑑𝑜 𝑠𝑢𝑚 = 𝑠𝑢𝑚 + 𝑗 ∗ 𝑘
𝑓𝑜𝑟 𝑘 = 𝑗 𝑡𝑜 𝑛 𝑑𝑜
𝑙 = 𝑙 + 1 𝑓𝑜𝑟 𝑙 = 1 𝑡𝑜 𝑛 𝑑𝑜 𝜽 𝒏
𝑠𝑢𝑚 = 𝑠𝑢𝑚 − 𝑙 + 1
𝒕 𝒏 = 𝜽 𝒏𝟑
printf(“sum is now %d”,𝒔𝒖𝒎) 𝜽 𝟏
Example 5:
𝑙 = 0 𝒕 𝒏 = 𝜽 𝒏𝟐 + 𝜽 𝒏 + 𝜽 𝟏
𝑓𝑜𝑟 𝑖 = 1 𝑡𝑜 𝑛 𝑑𝑜 𝒕 𝒏 = 𝜽 𝒏𝟐
𝑓𝑜𝑟 𝑗 = 1 𝑡𝑜 𝑛2 𝑑𝑜
𝑓𝑜𝑟 𝑘 = 1 𝑡𝑜 𝑛3 𝑑𝑜
𝑙 = 𝑙 + 1
𝒕 𝒏 = 𝜽 𝒏𝟔
54
Analyzing Control Statements
Example 7: Example 9:
𝑙 = 0 𝑙 = 0
𝑓𝑜𝑟 𝑖 = 1 𝑡𝑜 𝑛, 𝑖 = 𝑖 ∗ 𝑐 𝑑𝑜 𝑓𝑜𝑟 𝑖 = 1 𝑡𝑜 𝑛, 𝑖 = 𝑝𝑜𝑤(𝑖, 𝑐) 𝑑𝑜
𝑙 = 𝑙 + 1 𝑙 = 𝑙 + 1
𝒕 𝒏 = 𝜽(𝒍𝒐𝒈𝒏) 𝒕 𝒏 = 𝜽 𝒍𝒐𝒈𝒍𝒐𝒈𝒏
𝒕 𝒏 = 𝜽 𝒍𝒐𝒈𝒏 𝒕 𝒏 = 𝜽 𝒍𝒐𝒈𝒍𝒐𝒈𝒏
55
Recursion
56
Example:
int fun(int x)
{
if(x < 1)
return;
fun(x - 1);
printf("%d ",x);
}
57
Example:
int fun(int n) int fun(int n)
{ {
// wrong base case (it may cause stack overflow)
if (n < = 1) // base case
if (n == 100)
return 1; return 1;
else
else
return n + fun(n-1);
} return n + fun(n-1);
}
58
Algorithm to find factorial using recursion
Factorial of n
Factorial of any number n is denoted as n! and is equal to
n! = 1 x 2 x 3 x ... x (n – 2) x (n – 1) x n
Factorial of 3:
3! = 1 x 2 x 3
=6 int factorial(int n)
{
int fact = 1, i;
return fact;
}
59
Algorithm: FACTORIAL
Step 1: Start
Step 2: Read number n
Step 3: Call factorial(n)
Step 4: Print factorial f
Step 5: Stop
factorial(n)
Step 1: If n==1 then return 1
Step 2: Else
f=n*factorial(n-1)
Step 3: return f
60
FACTORIAL
int fun(int n)
{
if (n < = 1) // base case
return 1;
else
return n * fun(n-1);
}
61
Examples:
Output: 199
Output: 0 1 2 0 3 0 1
Output: 13
62
Sorting Algorithms
64
Bubble Sort – Example
Pass 1 :
34
45 swap 34 34 34
34
45 45 45 45
56 56 56
23 23
swap
23 23 23
56 56
12
swap
12 12 12 12
56
65
Bubble Sort – Example
Pass 2 : Pass 3 : Pass 4 :
34 34 34 23
34 23 12
23
swap
swap
45 45
23 23 23
34 34
12 12
23
swap
swap
23 23
45 45
12 12 12
34 34
swap
12 12 12
45 45 45 45
56 56 56 56 56 56
66
Bubble Sort - Algorithm
# Input: Array A
# Output: Sorted array A
Algorithm: Bubble_Sort(A)
for i ← 1 to n-1 do 𝛉 𝐧
for j ← 1 to n-i do
if A[j] > A[j+1] then
temp ← A[j] A[j+1])
swap(A[j], 𝛉 𝐧𝟐
A[j] ← A[j+1]
A[j+1] ← temp
67
Bubble Sort
It is a simple sorting algorithm that works by comparing each pair of adjacent items and
swapping them if they are in the wrong order.
The pass through the list is repeated until no swaps are needed, which indicates that the list is
sorted.
As it only uses comparisons to operate on elements, it is a comparison sort.
Although the algorithm is simple, it is too slow for practical use.
The time complexity of bubble sort is 𝜽 𝒏𝟐
68
Bubble Sort Algorithm – Best Case Analysis
# Input: Array A Pass 1 : i = 1
# Output: Sorted array A
12 j = 1
Algorithm: Bubble_Sort(A) 23 j = 2
int flag=1; 34 j = 3
for i ← 1 to n-1 do Condition never 45 j = 4
becomes true
for j ← 1 to n-i do 59
if A[j] > A[j+1] then Best case time
flag = 0; complexity = 𝜃 𝑛
swap(A[j],A[j+1])
if(flag == 1)
cout<<"already sorted"<<endl
break;
69
Selection Sort – Example 1
Sort the following elements in Ascending order
5 1 12 -5 16 2 12 14
Step 1 :
Unsorted Array
5 1 12 -5 16 2 12 14
1 2 3 4 5 6 7 8
Step 2 :
▪ Minj denotes the current index and Minx is the value stored
Unsorted Array (elements 2 to 8) at current index.
▪ So, Minj = 1, Minx = 5
-5
5 1 12 -5
5 16 2 12 14 ▪ Assume that currently Minx is the smallest value.
▪ Now find the smallest value from the remaining entire
1 2 3 4 5 6 7 8
Unsorted array.
Swap Index = 4, value = -5
70
Selection Sort – Example 1
Step 3 :
Unsorted Array (elements 3 to 8) ▪ Now Minj = 2, Minx = 1
▪ Find min value from remaining
-5 1 12 5 16 2 12 14 unsorted array
1 2 3 4 5 6 7 8
Index = 2, value = 1
Swap
71
Selection Sort – Example 1
Swap
72
Selection Sort – Example 1
Step 7 :
Unsorted Array ▪ Now Minj = 6, Minx = 16
(elements 7 to 8) ▪ Find min value from remaining
unsorted array
-5 1 2 5 12 12
16 16
12 14
1 2 3 4 5 6 7 8 Index = 7, value = 12
Swap
Step 8 :
Unsorted Array ▪ Minj = 7, Minx = 16
(element 8) ▪ Find min value from remaining
unsorted array
-5 1 2 5 12 12 14
16 16
14
Index = 8, value = 14
1 2 3 4 5 6 7 8
74
Selection Sort - Algorithm
# Input: Array A
# Output: Sorted array A
Algorithm: Selection_Sort(A)
for i ← 1 to n-1 do 𝛉 𝐧
minj ← i;
minx ← A[i];
for j ← i + 1 to n do
if A[j] < minx then
𝛉 𝐧 𝟐
minj ← j;
minx ← A[j];
A[minj] ← A[i];
A[i] ← minx;
75
Selection Sort – Example 2
Algorithm: Selection_Sort(A)
Pass 1 :
for i ← 1 to n-1 do
minj ← i; minx ← A[i]; i = 1
for j ← i + 1 to n do minj ← 12
if A[j] < minx then
34
minx ← 45 No Change
minj ← j ; minx ← A[j];
A[minj] ← A[i]; j = 2 3
A[i] ← minx; A[j] = 34
56
Sort in Ascending order
45 34 56 23 12
1 2 3 4 5
76
Selection Sort – Example 2
Algorithm: Selection_Sort(A)
Pass 1 :
for i ← 1 to n-1 do
minj ← i; minx ← A[i]; i = 1
for j ← i + 1 to n do 4
minj ← 2
5
if A[j] < minx then
minx ← 34
23
12
minj ← j ; minx ← A[j];
A[minj] ← A[i]; j = 2 3 4 5
A[i] ← minx; A[j] = 12
23
Sort in Ascending order Unsorted Array
45 34 56 23 12 45
12 34 56 23 45
12
1 2 3 4 5 1 2 3 4 5
Swap
45
12 23
34 34
56 34
45
23
56 45
56
77
Insertion Sort – Example
Sort the following elements in Ascending order
5 1 12 -5 16 2 12 14
Step 1 :
Unsorted Array
5 1 12 -5 16 2 12 14
1 2 3 4 5 6 7 8
Step 2 :
𝒋
𝒊 = 𝟐, 𝒙 = 𝟏 𝒋 = 𝒊 – 𝟏 𝒂𝒏𝒅 𝒋 > 𝟎
51 1 12 -5 16 2 12 14 while 𝑥 < 𝑇 𝑗 do
1 2 3 4 5 6 7 8 𝑇 𝑗+1 ←𝑇 𝑗
𝑗−−
Shift down
78
Insertion Sort – Example
Step 3 :
𝒋
𝒊 = 𝟑, 𝒙 = 𝟏𝟐 𝒋 = 𝒊 – 𝟏 𝒂𝒏𝒅 𝒋 > 𝟎
1 5 12 -5 16 2 12 14 while 𝑥 < 𝑇 𝑗 do
1 2 3 4 5 6 7 8 𝑇 𝑗+1 ←𝑇 𝑗
𝑗−−
𝒋
while 𝑥 < 𝑇 𝑗 do
𝒋
𝑇 𝑗+1 ←𝑇 𝑗
-5
1 5 12 -5 16 2 12 14 𝑗−−
1 2 3 4 5 6 7 8
Shift down
Shift down
Shift down
79
Insertion Sort – Example
Step 5 :
𝒋
𝒊 = 𝟓, 𝒙 = 𝟏𝟔 𝒋 = 𝒊 – 𝟏 𝒂𝒏𝒅 𝒋 > 𝟎
-5 1 5 12 16 2 12 14 while 𝑥 < 𝑇 𝑗 do
1 2 3 4 5 6 7 8 𝑇 𝑗+1 ←𝑇 𝑗
𝑗−−
No Shift will take place
Step 6 :
𝒊 = 𝟔, 𝒙 = 𝟐 𝒋 = 𝒊 – 𝟏 𝒂𝒏𝒅 𝒋 > 𝟎
𝒋 𝒋 while 𝑥 < 𝑇 𝑗 do
𝑇 𝑗+1 ←𝑇 𝑗
-5 1 52 12 16 2 12 14 𝑗−−
1 2 3 4 5 6 7 8
80
Insertion Sort – Example
Step 7 :
𝒋
𝒊 = 𝟕, 𝒙 = 𝟏𝟐 𝒋 = 𝒊 – 𝟏 𝒂𝒏𝒅 𝒋 > 𝟎
-5 1 2 5 12 12 14
12 16 while 𝑥 < 𝑇 𝑗 do
1 2 3 4 5 6 7 8 𝑇 𝑗+1 ←𝑇 𝑗
𝑗−−
Shift down
Step 8 :
𝒊 = 𝟖, 𝒙 = 𝟏𝟒 𝒋 = 𝒊 – 𝟏 𝒂𝒏𝒅 𝒋 > 𝟎
𝒋 while 𝑥 < 𝑇 𝑗 do
𝑇 𝑗+1 ←𝑇 𝑗
-5 1 2 5 12 12 14
16 14 𝑗−−
1 2 3 4 5 6 7 8
Algorithm: Insertion_Sort(T[1,…,n])
for i ← 2 to n do
𝛉 𝐧
x ← T[i];
j ← i – 1;
while x < T[j] and j > 0 do
T[j+1] ← T[j];
𝛉 𝐧𝟐
j ← j – 1;
T[j+1] ← x;
82
Insertion Sort Algorithm – Best Case Analysis
# Input: Array T Pass 1 :
# Output: Sorted array T
12
23 i=2 x=23 T[j]=12
Algorithm: Insertion_Sort(T[1,…,n])
34 i=3 x=34 T[j]=23
for i ← 2 to n do
𝛉 𝐧 45 i=4 x=45 T[j]=34
x ← T[i]; 59 i=5 x=59 T[j]=45
j ← i – 1;
while x < T[j] and j > 0 do The best case time complexity
T[j+1] ← T[j]; of Insertion sort is 𝜽 𝒏
j ← j – 1; The average and worst case
T[j+1] ← x; time complexity of Insertion
sort is 𝜽 𝒏𝟐
83
Analysis of Insertion Sort(alternate)
84
Comparison counting
34
45
56
23
12
85
Heap & Heap Sort Algorithm
Introduction
A heap data structure is a binary tree with the following two properties.
1. It is a complete binary tree: Each level of the tree is completely filled, except possibly the bottom level. At
this level it is filled from left to right.
2. It satisfies the heap order property: the data item stored in each node is greater than or equal to the
data item stored in its children node.
a a 9 9
b c b c 6 7 6 7
d e f d e f 2 4 8 2 4 1
Binary Tree but not a Heap Complete Binary Tree - Heap Not a Heap Heap
87
Array Representation of Heap
Heap can be implemented using an Array.
An array 𝐴 that represents a heap is an object with two attributes:
1. 𝑙𝑒𝑛𝑔𝑡ℎ[𝐴], which is the number of elements in the array, and
2. ℎ𝑒𝑎𝑝−𝑠𝑖𝑧𝑒[𝐴], the number of elements in the heap stored within array 𝐴
16
14 10
2 4 1 Heap 16 14 10 8 7 9 3 2 4 1
88
Array Representation of Heap
In the array 𝐴, that represents a heap
1. length[𝐴] = heap-size[𝐴]
2. For any node 𝒊 the parent node is 𝒊/𝟐
3. For any node 𝒋, its left child is 𝟐𝒋 and right child is 𝟐𝒋+𝟏
𝟐 𝟑
For node 𝑖 = 4,
14 10 Left child node is 2 ∗ 4 = node 8
Right child is 2 ∗ 4 + 1 = node 9
𝟒 𝟓 𝟔 𝟕
8 7 9 3
𝟏 𝟐 𝟑 𝟒 𝟓 𝟔 𝟕 𝟖 𝟗 𝟏𝟎
𝟖 𝟗 𝟏𝟎
2 4 1 Heap 16 14 10 8 7 9 3 2 4 1
89
Types of Heap
1. Max-Heap − Where the value of the root node is 9
greater than or equal to either of its children.
6 7
2 4 1
6 7 9
90
Introduction to Heap Sort
1. Build the complete binary tree using given elements.
2. Create Max-heap to sort in ascending order.
3. Once the heap is created, swap the last node with the root node and delete the last node from
the heap.
4. Repeat step 2 and 3 until the heap is empty.
91
Heap Sort – Example 1
Sort the following elements in Ascending order
4 10 3 5 1
4 10 3 5 1
10 3
92
Heap Sort – Example 1
Sort the following elements in Ascending order
4 10 3 5 1
93
Heap Sort – Example 1
Sort the following elements in Ascending order
4 10 3 5 1
94
Heap Sort – Example 1
Sort the following elements in Ascending order
4 10 3 5 1
10
1 5 3 4 1
10
5 3
Swap
95
Heap Sort – Example 1
Sort the following elements in Ascending order
4 10 3 5 1
1
4
96
Heap Sort – Example 1
Sort the following elements in Ascending order
4 10 3 5 1
51 4 3 15 10
4 3
Swap
97
Heap Sort – Example 1
Sort the following elements in Ascending order
4 10 3 5 1
98
Heap Sort – Example 1
Sort the following elements in Ascending order
4 10 3 5 1
13 13 4 5 10
3
1
Swap
99
Heap Sort – Example 1
Sort the following elements in Ascending order
4 10 3 5 1
1 3 4 5 10
100
Heap Sort – Example 2
Sort given element in ascending order using heap sort. 19, 7, 16, 1, 14, 17
19 14
7 16
17 1 14
7 16
17
19 19
7 16 14
7 17
16
1 14 17 1 14
7 16
17
101
Heap Sort – Example 2
Step 3 Step 4
19
16 14 17 1 7 16
19 17
16 14 17
16 1 7 19
16
19 17
16 Create Max-heap
Swap &
remove
14 17 the last 14 16
17
element
1 7 19
16 1 7
102
Heap Sort – Example 2
Step 5 Step 6
17
7 14 16 1 7
17 19 7
16 14 16
7 1 17 19
17
7 16
7 Create Max-heap
Swap &
remove
14 16 the last 14 7
16
element
1 17
7 1
103
Heap Sort – Example 2
Step 7 Step 8
16
1 14 7 1
16 17 19 1
14 14
1 7 16 17 19
16
1 1
14 Create Max-heap
Swap &
remove
14 7 the last 14
1 7
element
16
1
104
Heap Sort – Example 2
Step 9 Step 10
14
7 1 14
7 16 17 19 17 17 14 16 17 19
14
7 71 Already a Max-heap
Swap &
remove the Swap & remove the last
last element element
1 14
7 7
1
Step 11
1 7 14 16 17 19
Remove the
1
last element
The entire array is sorted now.
105
Exercises
Sort the following elements using Heap Sort Method.
1. 34, 18, 65, 32, 51, 21
2. 20, 50, 30, 75, 90, 65, 25, 10, 40
Sort the following elements in Descending order using Hear Sort Algorithm.
1. 65, 77, 5, 23, 32, 45, 99, 83, 69, 81
106
Heap Sort – Algorithm
# Input: Array A
# Output: Sorted array A
Algorithm: Heap_Sort(A[1,…,n])
BUILD-MAX-HEAP(A)
for i ← length[A] downto 2
do exchange A[1] ↔ A[i]
heap-size[A] ← heap-size[A] – 1
MAX-HEAPIFY(A, 1, n)
107
Heap Sort – Algorithm
Algorithm: BUILD-MAX-HEAP(A) 4 1 3 2 9 7
heap-size[A] ← length[A] 1
4
for i ← ⌊length[A]/2⌋ downto 1
2 3
do MAX-HEAPIFY(A, i) 1 3
4 5 6
heap-size[A] = 6 2 9 7
4 1 7 2 9 3 4 9 7 2 1 3 9 4 7 2 1 3
i=3 1 i=2 1 i=1 1
4 4 49
2 3 2 3 2 3
1 37 91 7 9
4 7
4 5 6 4 5 6 4 5 6
2 9 73 2 91 3 2 1 3
108
Heap Sort – Algorithm
# Input: Array A
# Output: Sorted array A 39 4 7 2 1 93
1
Algorithm: Heap_Sort(A[1,…,n]) 9
BUILD-MAX-HEAP(A) 2 3
for i ← length[A] downto 2 4 7
do exchange A[1] ↔ A[i] 4 5 6
heap-size[A] ← heap-size[A] – 1 2 1 3
MAX-HEAPIFY(A, 1, n)
109
Heap Sort – Algorithm
Algorithm: Max-heapify(A, i, n)
l ← LEFT(i) l ←2 1 3 4 7 2 1 9
r ← RIGHT(i) r ← 3 1
if l ≤ n and A[l] > A[i] 3
Yes
2 3
then largest ← l largest ← 2
4 7
else largest ← i 4 5
if r ≤ n and A[r] > A[largest] Yes 2 1
then largest ← r largest ← 3
if largest ≠ i Yes
then exchange A[i] ↔ A[largest]
MAX-HEAPIFY(A, largest, n)
110
Heap Sort – Algorithm
# Input: Array A
# Output: Sorted array A 3 4 7 2 1 9
1
Algorithm: Heap_Sort(A[1,…,n]) 7
BUILD-MAX-HEAP(A) 2 3
for i ← length[A] downto 2 4 3
do exchange A[1] ↔ A[i] 4 5
heap-size[A] ← heap-size[A] – 1 2 1
MAX-HEAPIFY(A, 1, n)
111
Heap Sort Algorithm – Analysis
# Input: Array A
# Output: Sorted array A
heap-size[A] ← length[A]
for i ← ⌊length[A]/2⌋ downto 1 𝒏Τ𝟐
Algorithm: Heap_Sort(A[1,…,n])
do MAX-HEAPIFY(A, i) 𝐎( 𝒍𝒐𝒈 𝒏)
BUILD-MAX-HEAP(A) 𝐎(𝒏 𝒍𝒐𝒈 𝒏)
for i ← length[A] downto 2
𝒏−𝟏
do exchange A[1] ↔ A[i]
heap-size[A] ← heap-size[A] – 1
MAX-HEAPIFY(A, 1, n) 𝑶(𝒏 − 𝟏) (𝒍𝒐𝒈𝒏)
112
Amortized Analysis
Introduction
If there are series of operations where the cost of single operation is very large and rest of the
operation cost less, then worst case running time complexity may not give a tighter bound.
Amortized Analysis is used for algorithms where an occasional operation is very slow, but
most of the other operations are faster.
The time required to perform a sequence of data structure operations is averaged over all
operations performed.
In Amortized Analysis, we analyze a sequence of operations and guarantee a worst case
average time which is lower than the worst case time of a particular expensive operation.
So, Amortized analysis can be used to show that the average cost of an operation is small even
though a single operation might be expensive.
114
Amortized Analysis Techniques
There are three most common techniques of amortized analysis,
1. The aggregate method
▪ A sequence of 𝑛 operation takes worst case time 𝑇(𝑛)
▪ Amortized cost per operation is 𝑇(𝑛)/𝑛
2. The accounting method
▪ Assign each type of operation an (different) amortized cost
▪ Overcharge some operations
▪ Store the overcharge as credit on specific objects
▪ Then use the credit for compensation for some later operations
3. The potential method
▪ Same as accounting method
▪ But store the credit as “potential energy” and as a whole.
115
Amortized Analysis - Example Incrementing a Binary Counter
116
Amortized Analysis - Example Aggregate Method
117
Aggregate Method
For 𝒌 = 𝟒 (no. of bits) and 𝒏 = 𝟖 (counter value) total number of flips of bit can be given as,
Total Flips = 15
118
Aggregate Method
Therefore, the total number of flips in the sequence is,
K-1
1 1 1 1 1 1
σ∝
𝑖=0 = + + + + …
2𝑖 20 21 22 23 24
119
Thank You!