DAA Notes
DAA Notes
of Algorithms
B.Tech (CSE)
NOTES
Prepared By-
UNIT-1
INTRODUCTION
Review:- Elementary Data Structures, Algorithms and its complexity(Time and Space), Analysing Algorithms,
Asymptotic Notations, Priority Queue, Quick Sort.
Recurrence relation:- Methods for solving recurrence(Substitution , Recursion tree, Master theorem), Strassen
multiplication.
Topperworld.in
Topperworld.in
What is Algorithm
He word Algorithm means “a process or set of rules to
be followed in calculations or other problem-solving
operations”. Therefore Algorithm refers to a set of
rules/instructions that step-by-step define how a work is
to be executed upon in order to get the expected results.
Why study Algorithm ?
The importance of algorithms is very high in today's
world but in reality, what we focus on is the result, be it
ios apps, android apps, or any other application. The
reason we have these resultant applications is the
Algorithm. If programming a building, then the
algorithm is the pillar programming is standing on, and
without pillars, there is no building. But why do we go
for algorithms instead of going for the application
directly? Let's get that from an example. Let's suppose
we are building something, and we have the result in
mind. We are not an expert, but still, we bring all the
necessary items and design that thing. It also looks like
Topperworld.in
what we had in mind. But it does not fulfill the purpose
we built it for. Do we have any use of it? This is what's
an algorithm for a program because it provides meaning
to the program. There is much reason to study
algorithms as it is used in almost every digital
application we use today. To showcase the value
algorithms have, here we have some of its applications.
Properties of Algorithm
All Algorithms must satisfy the following criteria -
1) Input
There are more quantities that are extremely supplied.
2) Output
At least one quantity is produced.
3) Definiteness
Each instruction of the algorithm should be clear and
unambiguous.
4) Finiteness
The process should be terminated after a finite number
of steps.
5) Effectiveness
Every instruction must be basic enough to be
carried out theoretically or by using paper and
pencil
Topperworld.in
For example,suppose you are cooking a recipe and you chop
vegetables which are not be used in the recipe then it is a waste of
time.
6)Independent
An algorithm should have step-by-step directions, which
should be independent of any programming code. It
should be such that it could be run on any of the
programming languages.
Topperworld.in
ii) Well-Defined Inputs: If an algorithm says to take
inputs, it should be well-defined inputs.
Topperworld.in
Advantages of Algorithms:
Disadvantages of Algorithms:
Topperworld.in
i)Writing an algorithm takes a long time so it is time-
consuming.
ii)Branching and Looping statements are difficult to
show in Algorithms.
Performance Analysis of Algorithm
There are two types are:
i) Time Complexity
ii) Space Complexity
Time Complexity
Time complexity is the amount of time taken
by an algorithm to run, as a function of the
length of the input. It measures the time taken
to execute each statement of code in an
algorithm. Upskilling with the help of
an introduction to algorithms free course will
help you understand time complexity clearly.
.
Topperworld.in
.
Topperworld.in
Analyzing Algorithm
Topperworld.in
Some Algorithm Control Structures are:
1. Sequencing
2. If-then-else
3. for loop
4. While loop
1. Sequencing:
Computation Time = tA + tB
= (max (tA,tB)
= (max (O (n), θ (n2)) = θ (n2)
Topperworld.in
2. If-then-else:
Topperworld.in
Total Computation = (max (tA,tB))
= max (O (n2), θ (n2) = θ (n2)
3. For loop:
The general format of for loop is:
Topperworld.in
Complexity of for loop:
The outer loop executes N times. Every time the outer
loop executes, the inner loop executes M times. As a
result, the statements in the inner loop execute a total
of N * M times. Thus, the total complexity for the two
loops is O (N2)
Consider the following loop:
1. for i ← 1 to n
2. {
3. P (i)
4. }
If the computation time ti for ( PI) various as a function
of "i", then the total computation time for the loop is
given not by a multiplication but by a sum i.e.
1. For i ← 1 to n
2. {
3. P (i)
4. }
Takes
Topperworld.in
If the algorithms consist of nested "for" loops, then the
total computation time is
For i ← 1 to n
{
For j ← 1 to n
{
P (ij)
}
}
Example:
Consider the following "for" loop, Calculate the total
computation time for the following:
1. For i ← 2 to n-1
2. {
3. For j ← 3 to i
4. {
5. Sum ← Sum+A [i] [j]
6. }
7. }
Solution:
Topperworld.in
The total Computation time is:
While loop:
The Simple technique for analyzing the loop is to
determine the function of variable involved whose value
decreases each time around. Secondly, for terminating
the loop, it is necessary that value must be a positive
integer. By keeping track of how many times the value
of function decreases, one can obtain the number of
repetition of the loop. The other approach for analyzing
"while" loop is to treat them as recursive algorithms.
Algorithm:
1. 1. [Initialize] Set k: =1, LOC: =1 and MAX: = DA
TA [1]
2. 2. Repeat steps 3 and 4 while K≤N
3. 3. if MAX<DATA [k],then:
4. Set LOC: = K and MAX: = DATA [k]
5. 4. Set k: = k+1
6. [End of step 2 loop]
7. 5. Write: LOC, MAX
8. 6. EXIT
Topperworld.in
Example:
The running time of algorithm array Max of computing
the maximum element in an array of n integer is O (n).
Solution:
1. 2 + 1 + n +4 (n-1) + 1=5n
2. 2 + 1 + n + 6 (n-1) + 1=7n-2
Topperworld.in
The best case T(n) =5n occurs when A [0] is the
maximum element. The worst case T(n) = 7n-2 occurs
when element are sorted in increasing order.
We may, therefore, apply the big-Oh definition with c=7
and n0=1 and conclude the running time of this is O (n).
Asymptotic Notation
Asymptotic Notation is used to describe the running
time of an algorithm - how much time an algorithm
takes with a given input, n.
Asymptotic Notation is a
way of comparing function that ignores constant factors
and small input sizes. Three notations are used to
calculate the running time complexity of an algorithm:
There are three different notations: big O, big Theta
(Θ), and big Omega (Ω).
Why is Asymptotic Notation Important?
1. They give simple characteristics of an algorithm's
efficiency.
2. They allow the comparisons of the performances of
various algorithms.
1) Big-O Notation
The Big-O notation describes the worst-case running
time of a program. We compute the Big-O of an
algorithm by counting how many iterations an
Topperworld.in
algorithm will take in the worst-case scenario with an
input of N. We typically consult the Big-O because we
must always plan for the worst case. For example,
O(log n) describes the Big-O of a binary search
algorithm.
1. f (n) ⩽ k.g (n)f(n)⩽k.g(n) for n>n0n>n0 in all case
For Example:
Topperworld.in
scenario based on an input of N. For example, a Bubble
Sort algorithm has a running time of Ω(N) because in
the best case scenario the list is already sorted, and the
bubble sort will terminate after the first iteration.
For Example:
f (n) =8n2+2n-3≥8n2-3
=7n2+(n2-3)≥7n2 (g(n))
Thus, k1=7
Hence, the complexity of f (n) can be represented as Ω
(g (n))
3. Theta (θ) Notation: The function f (n) = θ (g (n))
[read as "f is the theta of g of n"] if and only if there exists
positive constant k1, k2 and k0 such that
k1 * g (n) ≤ f(n)≤ k2 g(n)for all n, n≥ n0
Topperworld.in
3n+2= θ (n) as 3n+2≥3n and 3n+2≤ 4n, for n
k1=3,k2=4, and n0=2
Hence, the complexity of f (n) can be represented as θ
(g(n)).
Recurrence Relation
A recurrence is an equation or inequality that describes a
function in terms of its values on smaller inputs. To solve
a Recurrence Relation means to obtain a function defined
on the natural numbers that satisfy the recurrence.
For Example, the Worst Case Running Time T(n) of the
MERGE SORT Procedures is described by the
recurrence.
T (n) = θ (1) if n=1
2T + θ (n) if n>1
Topperworld.in
There are four methods for solving Recurrence:
1. Substitution Method
2. Iteration Method
4. Master Method
1. Substitution Method:
The Substitution Method Consists of two main steps:
T (n) = T +n
We have to show that it is asymptotically bound by O
(log n).
Topperworld.in
Solution:
For T (n) = O (log n)
We have to show that for some constant c
1. T (n) ≤c logn.
Put this in given Recurrence Equation.
T (n) ≤c log + 1
≤c log + 1 = c logn-clog2 2+1
≤c logn for c≥1
Thus T (n) =O logn.
Example2. Consider the Recurrence
T (n) = 2T + n n>1
Find an Asymptotic bound on T.
Solution:
Topperworld.in
2. Iteration Methods
It means to expand the recurrence and express it as a
summation of terms of n and initial condition.
Example1: Consider the Recurrence
1. T (n) = 1 if n=1
2. = 2T (n-1) if n>1
Topperworld.in
3) Recurrence Tree Method: In this method,
we draw a recurrence tree and calculate the time
taken by every level of tree. Finally, we sum the
work done at all levels. To draw the recurrence
tree, we start from the given recurrence and keep
drawing till we find a pattern among levels. The
pattern is typically a arithmetic or geometric
series.
1. In general, we consider the second term in recurrence
as root.
2. It is useful when the divide & Conquer algorithm is
used.
Topperworld.in
3. It is sometimes difficult to come up with a good guess.
In Recursion tree, each root and child represents the cost
of a single subproblem.
Topperworld.in
Example 3: Consider the following recurrence
Topperworld.in
When we add the values across the levels of the recursion
trees, we get a value of n for every level. The longest path
from the root to leaf is
Topperworld.in
4) Master Method
The Master Method is used for solving the following
types of recurrence
T (n) = a T + f (n)
In the function to the analysis of a recursive algorithm,
the constants and function take on the following
significance:
Topperworld.in
o It is not possible always bound the function
according to the requirement, so we make three
cases which will tell us what kind of bound we can
apply on the function
Priority queue
A priority queue is a special type of queue in which each element is associated
with a priority value. And, elements are served on the basis of their priority. That
is, higher priority elements are served first.
However, if elements with the same priority occur, they are served according to
their order in the queue.
The element with the highest value is considered the highest priority element.
However, in other cases, we can assume the element with the lowest value as the
highest priority element.
Topperworld.in
Removing highest Priority Element
Hence, we will be using the heap data structure to implement the priority queue in
this tutorial. A max-heap is implement is in the following operations. If you want
to learn more about it, please visit max-heap and mean-heap.
A comparative analysis of different implementations of priority queue is given
below.
Topperworld.in
Operations peek insert delete
Topperworld.in
Heapify after insertion
If there is no node,
create a newNode.
insert the newNode at the end (last node from left to right.)
For Min Heap, the above algorithm is modified so that parentNode is always smaller
than newNode .
Topperworld.in
• Select the element to be deleted.
Select the element to be deleted
Topperworld.in
• Heapify the tree. Heapify the
priority queue
remove noteToBeDeleted
For Min Heap, the above algorithm is modified so that the both childNodes are
smaller than currentNode .
Peek operation returns the maximum element from Max Heap or minimum
element from Min Heap without deleting the node.
Topperworld.in
return rootNode
Extract-Max returns the node with maximum value after removing it from a Max
Heap whereas Extract-Min returns the node with minimum value after removing it
from Min Heap.
Java
C++
Topperworld.in
# Swap and continue heapifying if root is not largest
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
heapify(arr, n, largest)
array.remove(size - 1)
arr = []
insert(arr, 3)
insert(arr, 4)
insert(arr, 9)
insert(arr, 5)
insert(arr, 2)
deleteNode(arr, 4)
print("After deleting an element: " + str(arr))
Topperworld.in
Heap Sort
Binary Heap:
Binary Heap is an array object can be viewed as
Complete Binary Tree. Each node of the Binary Tree
corresponds to an element in an array.
1. Length [A],number of elements in array
2. Heap-Size[A], number of elements in a heap stored
within array A.
The root of tree A [1] and gives index 'i' of a node that
indices of its parents, left child, and the right child can be
computed.
1. PARENT (i)
2. Return floor (i/2)
3. LEFT (i)
4. Return 2i
5. RIGHT (i)
6. Return 2i+1
Topperworld.in
Representation of an array of the above figure is given below:
The index of 20 is 1
48.3M
953
Exception Handling in Java - Javatpoint
Next
Stay
To find the index of the left child, we calculate 1*2=2
This takes us (correctly) to the 14.
Now, we go right, so we calculate 2*2+1=5
Topperworld.in
This takes us (again, correctly) to the 6.
Now, 4's index is 7, we want to go to the parent, so we
calculate 7/2 =3 which takes us to the 17.
Heap Property:
A binary heap can be classified as Max Heap or Min
Heap
1. Max Heap: In a Binary Heap, for every node I other
than the root, the value of the node is greater than or
equal to the value of its highest child
Topperworld.in
2. MIN-HEAP: In MIN-HEAP, the value of the node is
lesser than or equal to the value of its lowest child.
Topperworld.in
Heapify Method:
1. Maintaining the Heap Property: Heapify is a
procedure for manipulating heap Data Structure. It is
given an array A and index I into the array. The subtree
rooted at the children of A [i] are heap but node A [i]
itself may probably violate the heap property i.e. A [i] <
A [2i] or A [2i+1]. The procedure 'Heapify' manipulates
the tree rooted as A [i] so it becomes a heap.
MAX-HEAPIFY (A, i)
1. l ← left [i]
2. r ← right [i]
3. if l≤ heap-size [A] and A[l] > A [i]
4. then largest ← l
5. Else largest ← i
6. If r≤ heap-size [A] and A [r] > A[largest]
7. Then largest ← r
8. If largest ≠ i
9. Then exchange A [i] A [largest]
10. MAX-HEAPIFY (A, largest)
Analysis:
The maximum levels an element could move up are Θ
(log n) levels. At each level, we do simple comparison
which O (1). The total time for heapify is thus O (log n).
Building a Heap:
BUILDHEAP (array A, int n)
Topperworld.in
1 for i ← n/2 down to 1
2 do
3 HEAPIFY (A, i, n)
HEAP-SORT ALGORITHM:
HEAP-SORT (A)
1. BUILD-MAX-HEAP (A)
2. For I ← length[A] down to Z
3. Do exchange A [1] ←→ A [i]
4. Heap-size [A] ← heap-size [A]-1
5. MAX-HEAPIFY (A,1)
Analysis: Build max-heap takes O (n) running time. The
Heap Sort algorithm makes a call to 'Build Max-Heap'
which we take O (n) time & each of the (n-1) calls to
Max-heap to fix up a new heap. We know 'Max-Heapify'
takes time O (log n)
The total running time of Heap-Sort is O (n log n).
Topperworld.in
1. A = (5, 3, 17, 10, 84, 19, 6, 22, 9)
Solution: Originally:
Topperworld.in
6. If r≤ heap-size [A] and A [r] > A [largest]
7. 9≤9 and 9>22
8. If largest (8) ≠4
9. Then exchange A [4] ←→ A [8]
10. MAX-HEAPIFY (A, 8)
Topperworld.in
9. Then Exchange A [3] ←→ A [6]
10. MAX-HEAPIFY (A, 6)
Topperworld.in
10. Then Exchange A [2] ←→ A [5]
11. MAX-HEAPIFY (A, 5)
Topperworld.in
Priority Queue:
As with heaps, priority queues appear in two forms: max-
priority queue and min-priority queue.
A priority queue is a data structure for maintaining a set
S of elements, each with a combined value called a key.
A max-priority queue guides the following operations:
INSERT(S, x): inserts the element x into the set S,
which is proportionate to the operation S=S∪[x].
MAXIMUM (S) returns the element of S with the
highest key.
EXTRACT-MAX (S) removes and returns the element
of S with the highest key.
Topperworld.in
INCREASE-KEY(S, x, k) increases the value of
element x's key to the new value k, which is considered
to be at least as large as x's current key value.
Let us discuss how to implement the operations of a max-
priority queue. The procedure HEAP-MAXIMUM
consider the MAXIMUM operation in θ (1) time.
HEAP-MAXIMUM (A)
1. return A [1]
The procedure HEAP-EXTRACT-MAX implements the
EXTRACT-MAX operation. It is similar to the for loop
of Heap-Sort procedure.
HEAP-EXTRACT-MAX (A)
1 if A. heap-size < 1
2 error "heap underflow"
3 max ← A [1]
4 A [1] ← A [heap-size [A]]
5 heap-size [A] ← heap-size [A]-1
6 MAX-HEAPIFY (A, 1)
7 return max
The procedure HEAP-INCREASE-KEY implements the
INCREASE-KEY operation. An index i into the array
identify the priority-queue element whose key we wish
to increase.
HEAP-INCREASE-KEY.A, i, key)
Topperworld.in
1 if key < A[i]
2 errors "new key is smaller than current key"
3 A[i] = key
4 while i>1 and A [Parent (i)] < A[i]
5 exchange A [i] with A [Parent (i)]
6 i =Parent [i]
The running time of HEAP-INCREASE-KEY on an n-
element heap is O (log n) since the path traced from the
node updated in line 3 to the root has length O (log n).
The procedure MAX-HEAP-INSERT implements the
INSERT operation. It takes as an input the key of the new
item to be inserted into max-heap A. The procedure first
expands the max-heap by calculating to the tree a new
leaf whose key is - ∞. Then it calls HEAP-INCREASE-
KEY to set the key of this new node to its right value and
maintain the max-heap property
MAX-HEAP-INSERT (A, key)
1 A. heap-size = A. heap-size + 1
2 A [A. heap-size] = - ∞
3 HEAP-INCREASE-KEY (A, A. heap-size, key)
The running time of MAX-HEAP-INSERT on an n-
element heap is O (log n).
Example: Illustrate the operation of HEAP-EXTRACT-
MAX on the heap
Topperworld.in
1. A= (15,13,9,5,12,8,7,4,0,6,2,1)
Fig: Operation of HEAP-INCREASE-KEY
Fig: (a)
Topperworld.in
Fig: (b)
Fig: (c)
Topperworld.in
After one iteration of the while loop of lines 4-6, the node
and its parent have exchanged keys, and the index i
moves up to the parent.
Fig: (d)
Topperworld.in
HEAP-DELETE (A, i)
1. A [i] ← A [heap-size [A]]
2. Heap-size [A] ← heap-size [A]-1
3. MAX-HEAPIFY (A, i)
Quick sort
It is an algorithm of Divide & Conquer type.
Divide: Rearrange the elements and split arrays into two
sub-arrays and an element in between search that each
element in left sub array is less than or equal to the
average element and each element in the right sub- array
is larger than the middle element.
Conquer: Recursively, sort two sub arrays.
Combine: Combine the already sorted array.
• Quick Sort is a famous sorting algorithm.
• It sorts the given data items in ascending order.
Algorithm:
1. QUICKSORT (array A, int m, int n)
2. 1 if (n > m)
3. 2 then
4. 3 i ← a random index from [m,n]
Topperworld.in
5. 4 swap A [i] with A[m]
6. 5 o ← PARTITION (A, m, n)
7. 6 QUICKSORT (A, m, o - 1)
8. 7 QUICKSORT (A, o + 1, n)
Partition Algorithm:
Partition algorithm rearranges the sub arrays in a place.
1. PARTITION (array A, int m, int n)
2. 1 x ← A[m]
3. 2 o ← m
4. 3 for p ← m + 1 to n
5. 4 do if (A[p] < x)
6. 5 then o ← o + 1
7. 6 swap A[o] with A[p]
8. 7 swap A[m] with A[o]
9. 8 return o
Figure: shows the execution trace partition algorithm
Topperworld.in
Consider the following array has to be sorted in
ascending order using quick sort algorithm-
Topperworld.in
Step-01:
Initially-
• Left and Loc (pivot) points to the first element of
the array.
• Right points to the last element of the array.
Step-02:
Topperworld.in
Now, loc = 0, left = 0 and right = 4.
Step-03:
Topperworld.in
Now, loc = 4, left = 0 and right = 4.
Step-04:
Step-05:
Topperworld.in
As a[loc] > a[left], so algorithm moves left one position
towards right as-
Step-06:
Topperworld.in
Now, loc = 2, left = 2 and right = 4.
Step-07:
Topperworld.in
Now, loc = 2, left = 2 and right = 3.
Step-08:
Step-09:
Topperworld.in
As a[loc] > a[left], so algorithm moves left one position
towards right as-
Now,
• loc, left and right points at the same element.
• This indicates the termination of procedure.
Topperworld.in
Now, quick sort algorithm is applied on the left and
right sub arrays separately in the similar manner.
separately.
• If the array is split approximately in half (which is
log2n = O(nlog2n).
Advantages of Quick Sort-
Topperworld.in
(because its inner loop can be efficiently implemented
on most architectures)
• Quick Sort tends to make excellent usage of the
memory hierarchy like virtual memory or caches.
• Quick Sort can be easily parallelized due to its
Topperworld.in
T(N) = T(J) + T(N-J) + M(N)
The intuition is:
size J.
• T(N-J) = Time Complexity of Quick Sort for input
of size N-J.
• M(N) = Time Complexity of finding the pivot
J is from 0 to N-1
On solving for T(N), we will find the time complexity
of Quick Sort.
Topperworld.in
Best case Time Complexity of Quick Sort
O(Nlog(N))
•
color
• time complexity will be O(NlogN)
Explanation
Lets T(n) be the time complexity for best cases
n = total number of elements
then
T(n) = 2*T(n/2) + constant*n
2*T(n/2) is because we are dividing array into two array of equal size
constant*n is because we will be traversing elements of array in each level of tree
Topperworld.in
therefore,
T(n) = 2*T(n/2) + constant*n
further we will devide arrai in to array of equalsize so
T(n) = 2*(2*T(n/4) + constant*n/2) + constant*n == 4*T(n/4) + 2*constant*n
therefore,
T(n) = n * T(1) + n*logn = O(n*log2(n))
O(N^2)
•
Topperworld.in
n = total number of elements
Topperworld.in
T(n) = 1/n *[\sum_{i=1}^{n-1} T(i)] + 1/n*[\sum_{i=1}^{n-1} T(n-i)]
put n = n-1
(n-1)*T(n-1) = 2*[\sum_{i=1}^{n-2} T(i)] ............(2)
substract 1 and 2
then we will get
n*T(n) - (n-1)*T(n-1) = 2*T(n-1) + c*n^2 + c*(n-1)^2
n*T(n) = T(n-1)[2+n-1] + 2*c*n - c
n*T(n) = T(n-1)*(n+1) + 2*c*n [removed c as it was constant]
put n = n-1,
T(n-1)/n = T(n-2)/(n-1) + 2*c/n ............(4)
put n = n-2,
T(n-2)/n = T(n-3)/(n-2) + 2*c/(n-1) ............(5)
Topperworld.in
T(n)/(n+1) = T(1)/2 + 2*c*log(n) + C
T(n) = log(n)*(n+1)
therefore,
T(n) = O(n*log(n))
Space Complexity
• O(N)
Topperworld.in
For example, consider the following example:
T(n) = aT(n/b) + cn
Example
Example: T(n) = 2T(n/2) + n
Topperworld.in
As the recursion tree is complete, it remains to calculate
the total sum of the entries. For that, we first need to
determine the number of levels in the recursion tree.
Since each level of the tree splits each of the nodes in
that level to half the size of their parents, one can
conclude that the total number of levels here is log2n.
The next thing we note here is that in each level, the
sum of the nodes is n. Therefore, the overall time
complexity is given by:
T(n) = n + n + .... log2n times
= n ( 1 + 1 + ....log2n times)
= n log2n
= θ(n log2n)
Therefore, the overall time complexity of the operation
with the given recurrence equation is given by θ(n
log2n).
Topperworld.in
Example 1
Consider T (n) = 2T + n2
We have to obtain the asymptotic bound using recursion
tree method.
Solution: The Recursion tree for the above recurrence is
Topperworld.in
Example 2: Consider the following recurrence
T (n) = 4T +n
Obtain the asymptotic bound using recursion tree
method.
Solution: The recursion trees for the above recurrence
Topperworld.in
Example 3: Consider the following recurrence
When we add the values across the levels of the recursion trees, we get a value of n for every
level. The longest path from the root to leaf is
Topperworld.in
Master Theorem-
Topperworld.in
Case-01:
Case-02:
If a = bk and
• If p < -1, then T(n) = θ (nlogba)
• If p = -1, then T(n) = θ (n
log a 2
b .log n)
• If p > -1, then T(n) = θ (n
log a p+1
b .log n)
Case-03:
If a < bk and
• If p < 0, then T(n) = O (nk)
• If p >= 0, then T(n) = θ (n log n)
k p
Problem-01:
Topperworld.in
Solution-
Now, a = 3 and bk = 22 = 4.
Clearly, a < bk.
So, we follow case-03.
Since p = 0, so we have-
T(n) = θ (nklogpn)
T(n) = θ (n2log0n)
Thus,
T(n) = θ (n2)
Topperworld.in
Problem-02:
Solution-
Now, a = 2 and bk = 21 = 2.
Clearly, a = bk.
So, we follow case-02.
Since p = 1, so we have-
T(n) = θ (nlogba.logp+1n)
T(n) = θ (nlog22.log1+1n)
Topperworld.in
Thus,
T(n) = θ (nlog2n)
Problem-03:
Solution-
Since p = 0, so we have-
Topperworld.in
T(n) = θ (nklogpn)
T(n) = θ (n0.51log0n)
Thus,
T(n) = θ (n0.51)
Problem-04:
Solution-
Topperworld.in
Now, a = √2 = 1.414 and bk = 20 = 1.
Clearly, a > bk.
So, we follow case-01.
So, we have-
T(n) = θ (nlogba)
T(n) = θ (nlog2√2)
T(n) = θ (n1/2)
Thus,
T(n) = θ (√n)
Problem-05:
Solution-
Topperworld.in
• So, it can not be solved using Master’s theorem.
Problem-06:
Solution-
Topperworld.in
Now, a = 3 and bk = 31 = 3.
Clearly, a = bk.
So, we follow case-02.
Since p = 0, so we have-
T(n) = θ (nlogba.logp+1n)
T(n) = θ (nlog33.log0+1n)
T(n) = θ (n1.log1n)
Thus,
T(n) = θ (nlogn)
Problem-07:
A(n)
{
if(n<=1)
return 1;
Topperworld.in
else
return A(√n);
}
Solution-
Let-
n = 2m ……(1)
Then-
T(2m) = T(2m/2) + 1
Topperworld.in
So, we have-
S(m) = S(m/2) +1
Now, we can easily apply Master’s Theorem.
Now, a = 1 and bk = 20 = 1.
Clearly, a = bk.
So, we follow case-02.
Since p = 0, so we have-
S(m) = θ (mlogba.logp+1m)
S(m) = θ (mlog21.log0+1m)
S(m) = θ (m0.log1m)
Thus,
Topperworld.in
S(m) = θ(logm) ……(2)
Now,
• From (1), we have n = 2m.
• So, logn = mlog2 which implies m = log2n.
Topperworld.in
UNIT-2
Greedy algorithms:- Elements , Activity- Selection problem, Huffman codes, Task scheduling problem, Travelling
Salesman Problem.
Advanced data Structures:- Binomial heaps, Fibonacci heaps, Splay Trees, Red-Black Trees.
Topperworld.in
Dynamic Programming:-
Dynamic Programming is a technique in computer
programming that helps to efficiently solve a class of
problems that have overlapping subproblems
and optimal substructure property.
Topperworld.in
1. Overlapping sub problem
One of the main characteristics is to split the
problem into subproblem, as similar as divide and
conquer approach. The overlapping subproblem is
found in that problem where bigger problems share
the same smaller problem. However unlike divide
and conquer there are many subproblems in which
overlap cannot be treated distinctly or
independently. Basically, there are two ways for
handling the overlapping subproblems:
b.Bottom up approach
It is also termed as tabulation technique. In this,
all subproblems are needed to be solved in
advance and then used to build up a solution to
the larger problem.
2. Optimal sub structure
It implies that the optimal solution can be obtained
from the optimal solution of its subproblem. So
optimal substructure is simply an optimal selection
Topperworld.in
among all the possible substructures that can help
to select the best structure of the same kind to exist.
Example :
1. LCS(Longest Chain Subsequence)
2. MCM(Matrix Chain Multiplication)
Topperworld.in
C[i, 0] := 0
for j = 1 to n do
C[0, j] := 0
for i = 1 to m do
for j = 1 to n do
if xi = yj
C[i, j] := C[i - 1, j - 1] + 1
B[i, j] := ‘D’
else
if C[i -1, j] ≥ C[i, j -1]
C[i, j] := C[i - 1, j] + 1
B[i, j] := ‘U’
else
C[i, j] := C[i, j - 1]
B[i, j] := ‘L’
return C and B
Topperworld.in
Example: Given two sequences X [1...m] and Y [1.....n]. Find the longest
common subsequences to both.
That is:
Topperworld.in
Now for i=1 and j = 1
x1 and y1 we get x1 ≠ y1 i.e. A ≠ B
And c [i-1,j] = c [0, 1] = 0
c [i, j-1] = c [1,0 ] = 0
That is, c [i-1,j]= c [i, j-1] so c [1, 1] = 0 and b [1, 1] = ' ↑ '
Topperworld.in
Now for i=1 and j = 4
x1 and y4 we get. x1=y4 i.e A = A
c [1,4] = c [1-1,4-1] + 1
= c [0, 3] + 1
=0+1=1
c [1,4] = 1
b [1,4] = ' ↖ '
Topperworld.in
Now for i=2 and j = 1
We get x2 and y1 B = B i.e. x2= y1
c [2,1] = c [2-1,1-1] + 1
= c [1, 0] + 1
=0+1=1
c [2, 1] = 1 and b [2, 1] = ' ↖ '
Similarly, we fill the all values of c [i, j] and we get
Topperworld.in
Step 4: Constructing an LCS: The initial call is PRINT-LCS (b, X, X.length, Y.length)
PRINT-LCS (b, x, i, j)
1. if i=0 or j=0
2. then return
3. if b [i,j] = ' ↖ '
4. then PRINT-LCS (b,x,i-1,j-1)
5. print x_i
6. else if b [i,j] = ' ↑ '
7. then PRINT-LCS (b,X,i-1,j)
8. else PRINT-LCS (b,X,i,j-1)
Topperworld.in
From the table we can deduct that LCS = 6. There are several such sequences, for instance
(1,0,0,1,1,0) (0,1,0,1,0,1) and (0,0,1,1,0,1)
Topperworld.in
1. n length[p]-1
2. for i ← 1 to n
3. do m [i, i] ← 0
4. for l ← 2 to n // l is the chain length
5. do for i ← 1 to n-l + 1
6. do j ← i+ l -1
7. m[i,j] ← ∞
8. for k ← i to j-1
9. do q ← m [i, k] + m [k + 1, j] + pi-1 pk pj
10. If q < m [i,j]
11. then m [i,j] ← q
12. s [i,j] ← k
13. return m and s.
Topperworld.in
Let us proceed with working away from the diagonal. We compute the optimal solution for
the product of 2 matrices.
2. m (2, 3) = m2 x m3
= 10 x 3 x 3 x 12
= 10 x 3 x 12 = 360
3. m (3, 4) = m3 x m4
= 3 x 12 x 12 x 20
= 3 x 12 x 20 = 720
4. m (4,5) = m4 x m5
= 12 x 20 x 20 x 7
= 12 x 20 x 7 = 1680
Topperworld.in
o We initialize the diagonal element with equal i,j
value with '0'.
o After that second diagonal is sorted out and we get
all the values corresponded to it
Now the third diagonal will be solved out in the same
way.
Now product of 3 matrices:
M [1, 3] = M1 M2 M3
1. There are two cases by which we can solve this
multiplication: ( M1 x M2) + M3, M1+ (M2x M3)
Topperworld.in
M [1, 3] =264
As Comparing both output 264 is minimum in both cases
so we insert 264 in table and ( M1 x M2) + M3 this
combination is chosen for the output making.
M [2, 4] = M2 M3 M4
1. There are two cases by which we can solve this
multiplication: (M2x M3)+M4, M2+(M3 x M4)
2. After solving both cases we choose the case in which
minimum output is there.
M [2, 4] = 1320
As Comparing both output 1320 is minimum in both
cases so we insert 1320 in table and M2+(M3 x M4) this
combination is chosen for the output making.
M [3, 5] = M3 M4 M5
1. There are two cases by which we can solve this
multiplication: ( M3 x M4) + M5, M3+ ( M4xM5)
2. After solving both cases we choose the case in which
minimum output is there.
Topperworld.in
M [3, 5] = 1140
As Comparing both output 1140 is minimum in both
cases so we insert 1140 in table and ( M3 x M4) + M5this
combination is chosen for the output making.
M [1, 4] =1080
As comparing the output of different cases then '1080' is
minimum output, so we insert 1080 in the table and
Topperworld.in
(M1 xM2) x (M3 x M4) combination is taken out in output
making,
M [2, 5] = M2 M3 M4 M5
There are three cases by which we can solve this
multiplication:
1. (M2 x M3 x M4)x M5
2. M2 x( M3 x M4 x M5)
3. (M2 x M3)x ( M4 x M5)
After solving these cases we choose the case in which
minimum output is there
M [2, 5] = 1350
As comparing the output of different cases then '1350' is
minimum output, so we insert 1350 in the table and M2 x(
M3 x M4 xM5)combination is taken out in output making.
Topperworld.in
There are five cases by which we can solve this
multiplication:
1. (M1 x M2 xM3 x M4 )x M5
2. M1 x( M2 xM3 x M4 xM5)
3. (M1 x M2 xM3)x M4 xM5
4. M1 x M2x(M3 x M4 xM5)
After solving these cases we choose the case in which
minimum output is there
M [1, 5] = 1344
As comparing the output of different cases then '1344' is
minimum output, so we insert 1344 in the table and M1 x
M2 x(M3 x M4 x M5)combination is taken out in output
making.
Final Output is:
Topperworld.in
for storing m [i, j] costs an auxiliary table s [1.....n, 1.....n]
that record which index of k achieved the optimal costs
in computing m [i, j].
The algorithm first computes m [i, j] ← 0 for i=1, 2,
3.....n, the minimum costs for the chain of length 1.
Greedy Algorithm
A greedy algorithm is an approach for solving a
problem by selecting the best option available at the
moment. It doesn't worry whether the current best result
will bring the overall optimal result.
The algorithm never reverses the earlier decision even if
the choice is wrong. It works in a top-down approach.
This algorithm may not produce the best result for all
the problems. It's because it always goes for the local
best choice to produce the global best result.
2. Optimal Substructure
Topperworld.in
If the optimal overall solution to the problem corresponds to the optimal solution to
its subproblems, then the problem can be solved using a greedy approach. This
property is called optimal substructure.
i) Huffman Coding
ii) Knapsack problem
iii) Activity Selection Problem (ASP)
iv) Travelling Salesman Problem (TSP)
v) Task Scheduling
Huffman Coding is generally useful to compress the data in which there are
frequently occurring characters.
Topperworld.in
o Suppose we have 105 characters in a data file. Normal
Storage: 8 bits per character (ASCII) - 8 x 105 bits in a file.
But we want to compress the file and save it compactly.
Suppose only six characters appear in the file:
a 0
b 101
c 100
Topperworld.in
d 111
e 1101
f 1100
Topperworld.in
Example: Find an optimal Huffman Code for the
following set of frequencies:
1. a: 50 b: 25 c: 15 d: 40 e: 75
Solution:
Topperworld.in
i.e.
48.8M
785
Topperworld.in
Topperworld.in
Similarly, we apply the same process we get
Topperworld.in
Topperworld.in
Thus, the final output is:
Topperworld.in
2) Knapsack Problem:
The knapsack problem is a problem in combinational
optimization : Given a set of items, each with a weight
and a value, determine the number of each item to
include in a collection so that the total weight is less than
or equal to a given limit and the total value is as large as
possible.
For example, the weight of the container is 20 kg. We
have to select the items in such a way that the sum of the
weight of items should be either smaller than or equal to
the weight of the container, and the profit should be
maximum.
Maximize ∑n=1n ( xi . pi)
subject to constraint,
∑n=1n ( xi . wi ) ⩽ W
Topperworld.in
Algorithm: Greedy-Fractional-Knapsack (w [
1..n], p[1..n], W)
for i = 1 to n
do x[i] = 0
weight = 0
for i = 1 to n
if weight + w[i] ≤ W then
x[i] = 1
weight = weight + w[i]
else
x[i] = (W - weight) / w[i]
weight = W
break
return x
Topperworld.in
Let us arrange items by decreasing order of profit density.
Assume that items are labeled as X = (I1, I2, I3), have profit V
= {24, 25, 15} and weight W = {18, 15, 20}.
Topperworld.in
S = { I2 }, SW = 15, SP = 0 + 25 = 25
Iteration 2 : SW + w1 > M, so break down item I1.
The remaining capacity of the knapsack is 5 unit, so
select only 5 units of item I1.
frac = (M – SW) / W[i] = (20 – 15) / 18 = 5 / 18
S = { I2, I1 * 5/18 }
SP = SP + v1 * frac = 25 + (24 * (5/18)) = 25 + 6.67 =
31.67
SW = SW + w1 * frac = 15 + (18 * (5/18)) = 15 + 5 =
20
The knapsack is full. Fractional Greedy
algorithm selects items { I2, I1 * 5/18 }, and it gives a
profit of 31.67 units.
Problem: Find the optimal solution for knapsack problem (fraction) where
knapsack capacity = 28, P = {9, 5, 2, 7, 6, 16, 3} and w = {2, 5, 6, 11, 1, 9, 1}.
Solution:
Topperworld.in
Initialize, Weight = 0, P = 0, M = 28, S = { }
Where S is the solution set, P and W is profit and
weight of included items, respectively. M is the
capacity of the knapsack.
Iteration 1
(Weight + w5) ≤ M, so select I5
So, S = { I5 }, Weight = 0 + 1 = 1, P = 0 + 6= 6
Iteration 2
(Weight + w1) ≤ M, so select I1
So, S = {I5 ,I1 }, Weight = 1 + 2 = 3, P = 6 + 9= 15
Iteration 3
Topperworld.in
(Weight + w7) ≤ M, so select I7
o, S = {I5, I1, I7 }, Weight = 3 + 1 = 4, P = 15 + 3= 18
Iteration 4
(Weight + w6) ≤ M, so select I6
So, S = {I5, I1, I7, I6 }, Weight = 4 + 9 = 13, P = 18 +
16= 34
Iteration 5
(Weight + w2) ≤ M, so select I2
So, S = {I5, I1, I7, I6, I2 }, Weight = 13 + 5 = 18, P = 34
+ 5= 39
Iteration 6
(Weight + w4) > M, So I4 must be broken down into
two parts x and y such that x = capacity left in knapsack
and y = I4 – x.
Available knapsack capacity is 10 units. So we can
select only (28 – 18) / 11 = 0.91 unit of I4
So S = {I5, I1, I7, I6, I2, 0.91 * I4 }, Weight = 18 +
0.91*11 = 28, P = 39 + 0.91 * 7= 45.37
Topperworld.in
Activity Selection Problem
The activity selection problem is a mathematical
optimization problem. Our first illustration is the
problem of scheduling a resource among several
challenge activities. We find a greedy algorithm provides
a well designed and simple method for selecting a
maximum- size set of manually compatible activities.
• Span of activity is defined by its start time and
finishing time. Suppose we have such n activities.
• Aim of algorithm is to find optimal schedule with
maximum number of activities to be carried out
with limited resources. Suppose S = {a1, a2, a3, ..
an} is the set of activities that we want to schedule.
• Scheduled activities must be compatible with each
other. Start time of activities is let’s say si and
finishing time is fi, then activities i and j are called
compatible if and only if fi < sj or fj < si. In other
words, two activities are compatible if their time
durations do not overlap.
• Consider the below time line. Activities {A1, A3}
and {A2, A3} are compatible set of activities.
• For given n activities, there may exist multiple such
schedules. Aim of activity selection algorithm is to
find out the longest schedule without overlap.
Greedy Approach sort activities by their finishing time
in increasing order, so that f1 ≤ f2 ≤ f3 ≤ . . . ≤ fn. By
default it schedules the first activity in sorted list.
Subsequent next activities are scheduled whose start time
Topperworld.in
is larger than finish time of previous activity. Run
through all possible activities and do the same.
Algorithm for Activity Selection Problem
GREEDY- ACTIVITY SELECTOR (s, f)
// A is Set of n activities sorted by finishing time.
// S = { A[1] }, solution set, initially which contains first activity.
1. n ← length [s]
2. A ← {1}
3. j ← 1.
4. for i ← 2 to n
5. do if si ≥ fi
6. then A ← A ∪ {i}
7. j ← i
8. return A
Example: Given 10 activities along with their start and end time as
S = (A1 A2 A3 A4 A5 A6 A7 A8 A9 A10)
Si = (1,2,3,4,7,8,9,9,11,12)
fi = (3,5,4,7,10,9,11,13,12,14)
Topperworld.in
Now, schedule A1
Skip A5 as it is interfering.
Topperworld.in
Now we can understand another example :
Topperworld.in
In this example, we take the start and finish time of activities
as follows:
Topperworld.in
In this example, in all the activities 0, 1, 4 and 6 get selected,
while others get rejected.
1 2 3 4 5 6
di 4 2 4 3 1 4
wi 70 60 50 40 30 20
Solution: According to the Greedy algorithm we sort the jobs in decreasing order of their
penalties so that minimum of penalties will be charged.
In this problem, we can see that the maximum time for which uniprocessor machine will run
in 6 units because it is the maximum deadline.
w5 + w6 = 30 + 20 = 50 (2 3 4 1 7 5 6)
Other schedule is
Topperworld.in
(2 4 1 3 7 5 6)
costij =
Topperworld.in
The tour starts from area H1 and then select the minimum cost area reachable from H1.
Mark area H6 because it is the minimum cost area reachable from H1 and then select minimum
cost area reachable from H6.
Topperworld.in
Mark area H7 because it is the minimum cost area reachable from H6 and then select minimum
cost area reachable from H7.
Mark area H8 because it is the minimum cost area reachable from H8.
Topperworld.in
Mark area H5 because it is the minimum cost area reachable from H5.
Mark area H2 because it is the minimum cost area reachable from H2.
Topperworld.in
Mark area H3 because it is the minimum cost area reachable from H3.
Mark area H4 and then select the minimum cost area reachable from H4 it is H1.So, using the
greedy strategy, we get the following.
4 3 2 4 3 2 1 6
H1 → H6 → H7 → H8 → H5 → H2 → H3 → H4 → H1.
Binomial heaps
Topperworld.in
A binomial heap is a heap similar to a binary heap but also
supports quickly merging two heaps. This is achieved by
using a special tree structure. It is important as an
implementation of the mergeable heap
abstract data type (also called meldable heap), which is a
priority queue supporting merge operation.
Binomial tree
A binomial heap is implemented as a collection of binomial
trees (compare with a binary heap, which has a shape of a
single binary tree). A binomial tree is defined recursively:
• A binomial tree of order 0 is a single node
➢ Max-Heap :
In this heap, the key value of a node is greater than or equal to
the key value of the highest child.
Hence, H[Parent(i)] ≥ H[i]
• Max Heap conforms to the above properties of heap.
Topperworld.in
• In max heap, every node contains greater or equal value
element than its child nodes.
• Thus, root node contains the largest value element.
Min- heap:
In mean-heap, the key value of a node is lesser than or equal
to the key value of the lowest child.
Hence, H[Parent(i)] ≤ H[i]
In this context, basic operations are shown below with respect
to Max-Heap. Insertion and deletion of elements in and from
heaps need rearrangement of elements.
Hence, Heapify function needs to be called
• Min Heap conforms to the above properties of heap.
• In min heap, every node contains lesser value element
Topperworld.in
Properties of Binary Heap
All right, now with the basics out of the way, let's take a
closer look at the specific properties of the heap data
structure.
1. Ordering
Nodes must be arranged in an order according to values. The
values should follow min-heap or max-heap property.
In min-heap property, the value of each node, or child, is
greater than or equal to the value of its parent, with the
minimum value at the root node.
Topperworld.in
Min-heap
Topperworld.in
Max-heap
2. Structural
All levels in a heap should be full. In other words, it should be
a complete binary tree:
• All levels of heap should be full, except the last one.
• Nodes or child must be filled from left to right strictly.
• Heap doesn't follow binary search tree principle. The
values in right and left child or nodes don't matter.
Topperworld.in
Topperworld.in
Fibonacci Heap :
Topperworld.in
his Fibonacci Heap H consists of five Fibonacci Heaps and
16 nodes. The line with arrow head indicates the root list.
Minimum node in the list is denoted by min[H] which is
holding 4.
Splaying
After an element is accessed, the splay operation is
performed, which brings the element to the root of the tree. If
the element is not in a root position, splaying can take one of
three patterns:
1. Zig (or zag) step
2. Zig-zig (or zag-zag) step
Topperworld.in
3. Zig-zag (or zag-zig) step
The step you take is dependent on the position of the node. If
the node is at the root, it is immediately returned.
1. Zig (or zag)
When no grandparent node exists, the splay function will
move the node up to the parent with a single rotation. A left
rotation is a zag and a right rotation is a zig.
Topperworld.in
and the node is left of the parent), the operation is either zig-
zig (left) or zag-zag (right).
Topperworld.in
Red-Black tree is a self-balancing binary search tree in which
each node contains an extra bit for denoting the color of the
node, either red or black.
A red-black tree satisfies the following properties:
1. Red/Black Property: Every node is colored, either red
or black.
2. Root Property: The root is black.
3. Leaf Property: Every leaf (NIL) is black.
4. Red Property: If a red node has children then, the
children are always black.
5. Depth Property: For each node, any simple path from
this node to any of its descendant leaf has the same
black-depth (the number of black nodes).
Example
Topperworld.in
The tree above ensures that every path from the root to a leaf node has the same
amount of black nodes. In this case, there is one (excluding the root node).
Topperworld.in
UNIT-3
GRAPH ALGORITHMS
Review of graph algorithms:-Traversal Methods(Depth first and Breadth first search),Topological sort, Strongly connected components,
Minimum spanning trees- Kruskal and Prims, Single source shortest paths, Relaxation, Dijkstras Algorithm, Bellman- Ford algorithm,
Single source shortest paths for directed acyclic graphs, All pairs shortest paths- shortest paths and matrix multiplication, Floyd-
Warshall algorithm.
Computational Complexity:-Basic Concepts, Polynomial Vs Non-Polynomial Complexity, NP- hard and NP-complete classes.
Topperworld.in
Graph:-
It is a non -linear , non – primitive data
structure i.e. represented with a set of verticle that are
connected by edge i.e. G (V , e)
Topperworld.in
Classification of Graph
Term Description
Vertex Every individual data element is called a vertex or a node. In the above image,
Edge (Arc) It is a connecting link between two nodes or vertices. Each edge has two ends
Self-loop An edge is called a self-loop if its two endpoints coincide with each other.
Adjacency Vertices are said to be adjacent to one another if there is an edge connecting them.
Topperworld.in
Breadth-first search (BFS) is an algorithm that is used to
graph data or searching tree or traversing structures. The full
form of BFS is the Breadth-first search.
BFS is a graph traversal approach in
which you start at a source node and layer by layer through the graph,
analyzing the nodes directly related to the source node. Then, in BFS
traversal, you must move on to the next-level neighbor nodes.
Algorithm of BFS :
Algorithm of BFS ( G , s)
3.d[u] := ∞
4. π[u]=NIL
6.d[s]= NIL
7. d[s]:= NIL
8.Q= ɸ
9. ENQUEUE =( Q,s)
Topperworld.in
10.while (Q ≠ ɸ)
11.{ u=DEQUEUE(Q)
15.d[v]=d[u]+1
16.π[v]=u
Topperworld.in
In First Out (FIFO) principle, so the node's neighbors will be
viewed in the order in which it inserts them in the node,
starting with the node that was inserted first.
Application of DFS
i)Tropological Sort
ii)Strongly Connected Components
1)Tropological Sort :
Tropological sort is an algorithm which sorts a directed graph
by returning an array or a vector, or a list, that consists of
nodes where each node appears before all the nodes it points
to.
Here, we'll simply refer to it as an array, you can use a vector
or a list too.
Say we had a graph,
a --> b --> c
then the topological sort algorithm would return - [a, b, c].
Why? Because, a points to b, which means that a must come
before b in the sort. b points to c, which means that b must
come before c in the sort.
Let's take a graph and see the algorithm in action. Consider the graph
given below:
Topperworld.in
Initially in_degree[0]=0 and T is empty
Topperworld.in
So, we continue doing like this, and further iterations looks like as
follows:
Topperworld.in
Topperworld.in
So at last we get our Topological sorting in T i.e. : 0, 1, 2, 3, 4, 5
Initial Graph
The strongly connected components of the above graph are:
Topperworld.in
You can observe that in the first strongly connected component, every vertex can
reach the other vertex through the directed path.
1.Algorithm of DFS ( G )
2.for each vertex u ∈ V[G]
3.color u =WHITE
4.π[u]=NIL
5.Time =0;
6.for each value u ∈ V[G]
7.if ( color [u]= WHITE
8.DFS -VISIT (G ,u )
Algo DFS VISIT ( G , u )
Topperworld.in
1.Time = time +1; // white vertex ‘ u’ has just been
discover
2.d[u] = time
3.color[u] =GRAY
4.for each v ∈ Adj[u] in ‘G’ // explore edge ( V , v )
5.if ( color [v] =WHITE )
6.π[v]=u
7.DFS -VISIT ( G , V)
8.Color [u] =BLACK
9.Time =time +1
10.f[u] = time
15.d[v]=d[u]+1
16.π[v]=u
17. ENQUEUE (Q, v) }
18.Color [u]= BLACK }
Topperworld.in
the nodes u.
Starting node: A
Step 1: Create an adjacency list for the above graph.
Topperworld.in
tep 2: Create an empty stack.
Step 3: Push ‘A’ into the stack
Step 4: Pop ‘A’ and push ‘B’ and ‘F’. Mark node ‘A’
as the visited node
Topperworld.in
Step6: pop ‘D’ and push ‘C’. Mark ‘D’ as a visited
node.
Step 7: pop ‘C’ and push ‘E’. Mark ‘C’ as a visited node.
Topperworld.in
Step 8: pop ‘E’. Mark ‘E’ as a visited node. No new node is left.
Step 9: pop ‘B’. Mark ‘B’ as visited. All the nodes in the graph are visited now.
Topperworld.in
Minimum Spanning Tree
Before we learn about spanning trees, we need to understand two graphs:
undirected graphs and connected graphs.
An undirected graph is a graph in which the edges do not point in any direction
(ie. the edges are bidirectional).
Undirected Graph
A connected graph is a graph in which there is always a path from a vertex to any
other vertex.
Connected Graph
Spanning tree
Topperworld.in
A spanning tree is a sub-graph of an undirected connected graph, which includes
all the vertices of the graph with a minimum possible number of edges. If a vertex
is missed, then it is not a spanning tree.
Weighted graph
The possible spanning trees from the above graph are:
Topperworld.in
Minimum spanning tree - 2
Topperworld.in
Minimum spanning tree
The minimum spanning tree from a graph is found
using the two method in MST
i) Kruskal algorithm
ii) Prims algorithm
Kruskal's Algorithm :
Topperworld.in
In Kruskal's algorithm, we start from edges with the
lowest weight and keep adding the edges until the goal is
reached. The steps to implement Kruskal's algorithm are
listed as follows -
o First, sort all the edges from low weight to high.
o Now, take the edge with the lowest weight and add
it to the spanning tree. If the edge to be added creates
a cycle, then reject the edge.
o Continue to add the edges until we reach all vertices,
and a minimum spanning tree is created.
The applications of Kruskal's algorithm are -
o Kruskal's algorithm can be used to layout electrical
wiring among cities.
o It can be used to lay down LAN connections.
Algorithm of Kruskal :
1.{ constant a min -heap out of thr edge cost using
HEAPIFY
2. fir I =1 to n ;
3. do parent [i] =1 // each vertex is in a different set
4. i=0; min cost =0;
5. while ( ( i<n-1) && ( heap not empty)) do
Topperworld.in
6.{ Delete 0 min cost edge (u,v) from the heap & re-
heapify using ADJUST
7. j= FIND (u) ,k = FIND (v)
8.if ( j ≠ k)
9. { i= i+1
10. t [ i ,1] =u , t[i,z]=v;
11. Min cost = min cost + cost ( u, v)
12. UNION (j , k);
13.}}
14. if (i≠ n-1) then write ( No spanning Tree is possible else return
Min cost
15.}
Topperworld.in
Step 1 - First, add the edge AB with weight 1 to the
MST.
Topperworld.in
Step 2 - Add the edge DE with weight 2 to the MST as
it is not creating the cycle.
Topperworld.in
Step 4 - Now, pick the edge CD with weight 4 to the
MST, as it is not forming the cycle.
Topperworld.in
So, the final minimum spanning tree obtained from the
given weighted graph by using Kruskal's algorithm is -
Prims Algorithm
Topperworld.in
➢ It is used for finding the Minimum Spanning
Tree (MST) of a given graph.
Topperworld.in
16.then near [k] =I }
17.return Min cost }
Solution-
Step-01:
Topperworld.in
Step-02:
Step-03:
Step-04:
Topperworld.in
Step-05:
Step-06:
Topperworld.in
Since all the vertices have been included in the MST, so
we stop.
Problem-02:
Topperworld.in
Solution-
Topperworld.in
The Single-Source Shortest Path (SSSP) problem
consists of finding the shortest paths between a given
vertex v and all other vertices in the graph. Algorithms
such as Breadth-First-Search (BFS) for unweighted
graphs or Dijkstra [1] solve this problem.
In a shortest- paths
problem, we are given a weighted, directed graphs G =
(V, E), with weight function w: E → R mapping edges
to real-valued weights. The weight of path p = (v0,v1,.....
vk) is the total of the weights of its constituent edges:
1) Dijkstra’s Algorithm,
2) Bellman Ford Algorithm
b) ALGORITHM RELAXATION ( u , v , w)
1.if d[v]> d[u] + w[ u , v]
2.then d[v]=d[u]+w[u ,v]
Topperworld.in
Here,
W= denotes the weight of the edges
r = Source code
t= destination node
u = any intermediate node
1.for I =1to n do
2 { r [ i ] = false , dist [ i ] = cost [ v , i] } //
initialize s
3. r[v]=true , dist[v]=0.0 // put v in s
4.for sum = 2 to n-1 do // determine “ n-1”
path from
5.{ choose ‘u’ among those vertex not in ‘s’
Topperworld.in
such that d[ u] is minimum
6. r[u] = true // put ‘u’ in s
7. for ( each w adjacent to ‘u’ with r [ w] = fix
)
8.if ( d[w]>d[u] + cost[u,w]) then // relaxctive
of edge
9. d[w] = d[u] + cost[ u,w]
10.}
In this algorithm ,
v = source node
u = intermediate node
cost = the weight of the edge
d = distance from source node
n= total no. of vertice
Topperworld.in
‘S’ define the set which is intically empty &
the vertices are choosen in set as according to
the Shortest distance .
The algorithm will generate the shortest path from node 0 to all the other nodes
in the graph.
Note : For this graph, we will assume that the weight of the edges represents the
distance between two nodes.
We will have the shortest path from node 0 to node 1, from node 0 to node 2,
from node 0 to node 3, and so on for every node in the graph.
Initially, we have this list of distances (please see the list below):
• The distance from the source node to itself is 0. For this example, the
source node will be node 0 but it can be any node that you choose.
• The distance from the source node to all other nodes has not been
determined yet, so we use the infinity symbol to represent this initially.
Topperworld.in
We also have this list (see below) to keep track of the nodes that have not been
visited yet (nodes that have not been included in the path):
Note: Since we are choosing to start at node 0, we can mark this node as visited.
Equivalently, we cross it off from the list of unvisited nodes and add a red
border to the corresponding node in diagram:
Now we need to start checking the distance from node 0 to its adjacent nodes.
As you can see, these are nodes 1 and 2 (see the red edges):
Topperworld.in
After updating the distances of the adjacent nodes, we need to:
• Select the node that is closest to the source node based on the current
known distances.
• Mark it as visited.
• Add it to the path.
If we check the list of distances, we can see that node 1 has the shortest distance
to the source node (a distance of 2), so we add it to the path.
In the diagram, we can represent this with a red edge:
We mark it with a red square in the list to represent that it has been "visited" and
that we have found the shortest path to this node:
Topperworld.in
Now we need to analyze the new adjacent nodes to find the shortest
path to reach them. We will only analyze the nodes that are adjacent
to the nodes that are already part of the shortest path (the path
marked with red edges).
Node 3 and node 2 are both adjacent to nodes that are already in the
path because they are directly connected to node 1 and node 0,
respectively, as you can see below. These are the nodes that we will
analyze in the next step.
Since we already have the distance from the source node to node 2 written down
in our list, we don't need to update the distance this time. We only need to
update the distance from the source node to the new adjacent node (node 3):
Topperworld.in
Now that we have the distance to the adjacent nodes, we have to choose which
node will be added to the path. We must select the unvisited node with the
shortest (currently known) distance to the source node.
From the list of distances, we can immediately detect that this is node 2 with
distance 6:
We add it to the path graphically with a red border around the node and a red
edge:
We also mark it as visited by adding a small red square in the list of distances
and crossing it off from the list of unvisited nodes:
Now we need to repeat the process to find the shortest path from the source
node to the new adjacent node, which is node 3.
You can see that we have two possible paths 0 -> 1 -> 3 or 0 -> 2 -> 3. Let's see
how we can decide which one is the shortest path.
Topperworld.in
Node 3 already has a distance in the list that was recorded previously (7, see the
list below). This distance was the result of a previous step, where we added the
weights 5 and 2 of the two edges that we needed to cross to follow the path 0 ->
1 -> 3.
But now we have another alternative. If we choose to follow the path 0 -> 2 ->
3, we would need to follow two edges 0 -> 2 and 2 -> 3 with
weights 6 and 8, respectively, which represents a total distance of 14.
Clearly, the first (existing) distance is shorter (7 vs. 14), so we will choose to
keep the original path 0 -> 1 -> 3. We only update the distance if the new
path is shorter.
Therefore, we add this node to the path using the first alternative: 0 -> 1 -> 3.
We mark this node as visited and cross it off from the list of
unvisited nodes:
Topperworld.in
Now we repeat the process again.
We need to check the new adjacent nodes that we have not visited so far. This
time, these nodes are node 4 and node 5 since they are adjacent to node 3.
We update the distances of these nodes to the source node, always trying to find
a shorter path, if possible:
• For node 4: the distance is 17 from the path 0 -> 1 -> 3 -> 4.
• For node 5: the distance is 22 from the path 0 -> 1 -> 3 -> 5.
Topperworld.in
We also mark it as "visited" by adding a small red square in the list:
For node 5:
Topperworld.in
• The first option is to follow the path 0 -> 1 -> 3 -> 5, which has a distance
of 22 from the source node (2 + 5 + 15). This distance was already
recorded in the list of distances in a previous step.
• The second option would be to follow the path 0 -> 1 -> 3 -> 4 -> 5,
which has a distance of 23 from the source node (2 + 5 + 10 + 6).
Clearly, the first path is shorter, so we choose it for node 5.
For node 6:
• The path available is 0 -> 1 -> 3 -> 4 -> 6, which has a distance
of 19 from the source node (2 + 5 + 10 + 2).
We mark the node with the shortest (currently known) distance as visited. In this case,
node 6.
Topperworld.in
Only one node has not been visited yet, node 5. Let's see how we can
include it in the path.
There are three different paths that we can take to reach node 5 from
the nodes that have been added to the path:
• Option 1: 0 -> 1 -> 3 -> 5 with a distance of 22 (2 + 5 + 15).
• Option 2: 0 -> 1 -> 3 -> 4 -> 5 with a distance of 23 (2 + 5 + 10
+ 6).
• Option 3: 0 -> 1 -> 3 -> 4 -> 6 -> 5 with a distance of 25 (2 + 5
+ 10 + 2 + 6).
We select the shortest path: 0 -> 1 -> 3 -> 5 with a distance of 22.
We mark the node as visited and cross it off from the list of
unvisited nodes:
Topperworld.in
And voilà! We have the final result with the shortest path from
node 0 to each node in the graph.
In the diagram, the red lines mark the edges that belong to the
shortest path. You need to follow these edges to follow the shortest
path to reach a given node in the graph starting from node 0.
2. Bellman-Ford algorithm
Topperworld.in
do
5. { for each ( i, u) in the graph do
6.{ if ( do[u] > d[i] + cost [i, u]
Then d[u]=d[i] + cost [i, u]
7.}}}
In this Algorithm
➢ Bellman Ford algorithm helps us find the shortest path from a vertex to all
other vertices of a weighted graph.
By doing this repeatedly for all vertices, we can guarantee that the result is
optimized.
Topperworld.in
Step-1 for Bellman Ford's algorithm
Topperworld.in
Step-3 for Bellman Ford's algorithm
Topperworld.in
Step-5 for Bellman Ford's algorithm
Topperworld.in
➢ Single Source shortest path is basically the
shortest distance between the source and other
vertices in the graph.
Topperworld.in
Step1: To topologically sort vertices apply DFS (Depth
First Search) and then arrange vertices in linear order
by decreasing order of finish time.
Topperworld.in
Now, take each vertex in topologically sorted order and
relax each edge
Topperworld.in
5. d [x] ← 2
1. adj [t] → r, x
2. 3 + 1 < ∞
3. d [r] ← 4
4. 3 + 5 ≤ 2
1. adj [x] → y
2. 2 - 3 < ∞
3. d [y] ← -1
1. adj [y] → r
2. -1 + 4 < 4
3. 3 <4
4. d [r] ← 3
Topperworld.in
Thus the Shortest Path is:
1. s to x is 2
2. s to y is -1
3. s to t is 3
4. s to r is 3
Computational complexity
Topperworld.in
There are lots of variants of this bit that we are generally
looking at when we are doing any computer programming or
in general or in most practical purposes are just two main
complexities, one is Time Complexity, and the other is Space
(memory) Complexity.
Topperworld.in
i = 1; 1s
while( i<=10) 11s
{
result = i * a; 10s
printf(“\n” /d”, result); 10s
i++; 10s
}
Execution Time : 43s
Memory (Space) : 6 Bytes
NP -hard:
An NP-hard problem is at least as hard as the hardest
problem in NP and it is the class of the problems such
that every problem in NP reduces to NP-hard.
NP- Complete
NP-complete problem, any of a class of computational
problems for which no efficient solution algorithm has been
found.
Topperworld.in
Many significant computer-science problems belong
to this class—e.g., the traveling salesman problem,
satisfiability problems, and graph-covering problems.
Topperworld.in
UNIT-4
Topperworld.in
Flow Network:
Flow Network is a directed graph that
is used for modeling material Flow.
There are two different vertices; one is
a source which produces material at some steady rate,
and another one is sink which consumes the content at
the same constant speed.
Topperworld.in
2. There are two distinguishing points, the source s, and the
sink t;
3. For every vertex v ∈ V, there is a path from s to t
containing v.
Topperworld.in
The value of the flow is the net flow from the source,
Topperworld.in
The positive net flow leaving a vertex is described
symmetrically. One interpretation of the Flow-Conservation
Property is that the positive net flow entering a vertex other
than the source or sink must equal the positive net flow leaving
the vertex.
A flow f is said to be integer-valued if f (u, v) is an integer for
all (u, v) ∈ E. Clearly, the value of the flow is an integer is an
integer-valued flow.
Comparison Networks
Topperworld.in
A sorting network is a comparison network for which the
output sequence is monotonically increasing (that is b1≤ b2 ≤
....bn) for every input sequence.
Fig: A Sorting network based on Insertion Sort
Topperworld.in
Problem 2: The multiple source and sink maximum flow
problem is similar to the maximum flow problem, except there
is a set {s1,s2,s3.......sn} of sources and a set {t1,t2,t3..........tn} of
sinks.
Fortunately, this problem is no solid than regular maximum
flow. Given multiple sources and sink flow network G, we
define a new flow network G' by adding
o A super source s,
o A super sink t,
o For each si, add edge (s, si) with capacity ∞, and
o For each ti,add edge (ti,t) with capacity ∞
Figure shows a multiple sources and sinks flow network and an
equivalent single source and sink flow network
Topperworld.in
When the net flow f (u, v) is negative, the residual capacity
cf (u,v) is greater than the capacity c (u, v).
For Example: if c (u, v) = 16 and f (u, v) =16 and f (u, v) = -4,
then the residual capacity cf (u,v) is 20.
Given a flow network G = (V, E) and a flow f, the residual
network of G induced by f is Gf = (V, Ef), where
That is, each edge of the residual network, or residual edge, can
admit a strictly positive net flow.
Augmenting Path: Given a flow network G = (V, E) and a
flow f, an augmenting path p is a simple path from s to t in the
residual networkGf. By the solution of the residual network,
each edge (u, v) on an augmenting path admits some additional
positive net flow from u to v without violating the capacity
constraint on the edge.
Let G = (V, E) be a flow network with flow f. The residual
capacity of an augmenting path p is
Topperworld.in
Ford – Fulkerson Algorithm
Topperworld.in
A term, flow network, is used to describe a network of vertices and edges with a
source (S) and a sink (T). Each vertex, except S and T, can receive and send an
equal amount of stuff through it.
FORD-FULKERSON (G, s, t)
1. for each edge (u, v) ∈ E [G]
2. do f [u, v] ← 0
3. f [u, v] ← 0
4. while there exists a path p from s to t in the residual
network Gf.
5. do cf (p)←min? { Cf (u ,v):(u ,v)is on p}
6. for each edge (u, v) in p
7. do f [u, v] ← f [u, v] + cf (p)
8. f [u, v] ←f[ u ,v]
Topperworld.in
Solution: The left side of each part shows the residual
network Gf with a shaded augmenting path p,and the right side
of each part shows the net flow f.
Topperworld.in
Topperworld.in
Maximum Bipartite matching
Topperworld.in
Finding a maximum bipartite matching
We can use the Ford-Fulkerson method to find a maximum
matching in an undirected bipartite graph G= (V, E) in time
polynomial in |V| and |E|. The trick is to construct a flow
network G= (V',E') for the bipartite graph G as follows. We let
the source s and sink t be new vertices not in V, and we let V'=V
∪{s,t}.If the vertex partition of G is V = L∪R, the directed
edges of G' are the edges of E, directed from L to R, along with
|V| new directed edges:
Topperworld.in
Algorithm of Maximum Bipartite
matching:
1.bool kuhn(vertex v) {
2. if (used[v]) return false;
3. used[v] = true;
4. for (vertex q adjacent to v) {
5. if ((q has no pair) or kuhn(pairs[q])) {
6. pairs[q] = v;
7. return true;
8. }
9. }
10.}
11.find_max_matching {
12. for (vertex v = {
13. 1,
14. ..,
15. n
16. }) {
17. used = {
18. 0
19. };
20. kuhn(v);
21. }
22.}
Topperworld.in
The zero -one principal
Topperworld.in
Theorem (Zero-one principle) If a comparison network with
n inputs sorts all 2n possible sequences of 0’s and 1’s
correctly, then it sorts all sequences of arbitrary numbers
correctly.
Proof
Suppose for the purpose of contradiction that the
network sorts all zero-one sequences, but there exists a
sequence of arbitrary numbers that the network does not
correctly sort. That is, there exists an input sequence ha1,a2,. .
. ,ani containing elements ai and aj such that ai < aj , but the
network places aj before ai in the output sequence. We define
a monotonically increasing function f as
Topperworld.in
sorts the n − 1 zero-one sequences <1, 0, 0, . . . ,0, 0>, <1, 1,
0, . . . ,0, 0>, . . ., <1, 1, 1, . . . ,1, 0>.
Topperworld.in
produces two bitonic sequences of half the size such
that every element in the top half is at least as small as
each element in the bottom half. Thus, we can complete
the sort by utilizing two copies of BITONIC-SORTER
[n/2] to sort the two halves recursively.
Topperworld.in
An array with A[0…i…n-1] is said to be bitonic, if there is an
index i, such that
1. A[0] < A[1] < A[2] .... A[i1] < A[i] > A[i+1] > A[i+2] > A[i+3] > ... >A[
n-1]
Where, 0 ≤ i ≤ n-1.
Before moving directly towards the algorithm of bitonic sort,
first, understand the conversion of any random sequence into a
bitonic sequence.
How to convert the random sequence into a bitonic sequence?
Consider a sequence A[ 0 ... n-1] of n elements. First, start
constructing a Bitonic sequence by using 4 elements of the
sequence. Sort the first 2 elements in ascending order and the
last 2 elements in descending order, concatenate this pair to
form a Bitonic sequence of 4 elements. Repeat this process for
the remaining pairs of the element until we find a Bitonic
sequence.
Let's understand the process to convert the random sequence
into a bitonic sequence using an example.
Suppose the elements of array are - {30, 70, 40, 80, 60, 20, 10, 50}
Topperworld.in
Merging Network
Merging Network is the network that can join two sorted input sequences into one sorted output
sequence. We adapt BITONIC-SORTER [n] to create the merging network MERGER [n].
Given two sorted sequences, if we reverse the order of the second sequence and
then connect the two sequences, the resulting sequence is bitonic.
Topperworld.in
The recurrence given the depth of SORTER [n]
Topperworld.in