Module 2 Daa

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 34

lOMoAR cPSD| 29148908

Module 2: DISJOINT SETS, DIVIDE AND CONQUER

Disjoint Sets: Operations, Union and Find algorithms.


Divide and Conquer: General method, Defective chess board, Binary search, Finding maximum
and minimum, Merge sort, Strassen’s matrix multiplication.

DISJOINT SETS : Sets are represented by pair wise disjoint sets. If S i and Sj are two sets and i # j, then
there is no common elements for Si and Sj .
Example : When N = 10 elements. That can be partitioned into three disjoint sets i.e, S1, S2 and S3.

S1 = { 1, 7, 8, 9 } S2 = { 2, 5, 10 } S3 = { 3, 4, 6 }

Sets can be represented in 3 ways


1 : Tree Representation
2 : Data Representation
3 : Array Representation
1 : Tree Representation : The set will be represented as the tree structure where all children will store
the address of parent / root node. The root node will store null at the place of parent address. In the
given set of elements any element can be selected as the root node, generally we select the first node as
the root node.
Example: S1 = { 1, 7, 8, 9 } S2 = { 2, 5, 10 } S3 = { 3, 4, 6 } , Then these sets can be represented as

S1 S2 S3

2: Data Representation: We need to maintain the name of each set. So, we require one more data
structure to store the set names. The data structure contains two fields. One is the set name and the other
one is the pointer to root. The data representation for S1, S2 and S3.

Example: S1 = { 1, 7, 8, 9 } S2 = { 2, 5, 10 } S3 = { 3, 4, 6 }
lOMoAR cPSD| 29148908

3 : Array Representation : To represent the sets, we use an array of 1 to n elements where n is the
maximum value among the elements of all sets. The index values represent the nodes (elements of set)
and the entries represent the parent node. For the root value the entry will be‘-1’.
Array Representation of the sets S1, S2 and S3
Example: S1 = { 1, 7, 8, 9 } S2 = { 2, 5, 10 } S3 = { 3, 4, 6 }

S1 S2 S3

i 1 2 3 4 5 6 7 8 9 10

p -1 5 -1 3 -1 3 1 1 1 5
lOMoAR cPSD| 29148908

Disjoint Set Operations : Disjoint set supports two operations


1. Union
2. Find
1 : Disjoint set Union : If Si and Sj are two disjoint sets, then their union Si U Sj = { all elements x such
that s is in Si or Sj }
Example : S1 = { 1, 7, 8, 9 } S2 = { 2, 5, 10 }
S1 U S2 = { 1, 7, 8, 9 , 2, 5, 10 }

To perform disjoint set union between two sets Si and Sj can take any one root and make it sub-tree of the
other.
Example : S1 = { 1, 7, 8, 9 } S2 = { 2, 5, 10 } ,Then S1 U S2 can be represented as any one of the following.

2 : Find ( i ) : Given the element i, find the set containing i.

Example: S1 = { 1, 7, 8, 9 } S2 = { 2, 5, 10 } S3 = { 3, 4, 6 }

Find ( 4 ) = 4 is in set S3
Find ( 9 ) = 9 is in set S1
Find ( 10 ) = 10 is in set S2
lOMoAR cPSD| 29148908

UNION AND FIND ALGORITHMS :


1 : Simple Union
2 : Weighted Union
3 : Find
4 : Collapsing Find
1 : Simple Union : To perform union the SimpleUnion(i,j) function takes the inputs as the set roots i and j .
And make the parent of i as j i.e, make the second root as the parent of first root.
Algorithm :
Algorithm SimpleUnion (i,j)
{
P[i]:=j;
}
Example : union ( 1, 3 )

( or )

The SimpleUnion(i,j), algorithm is very easy to state, their performance characteristics are not very good.

If we want to perform following sequence of operations

Union(1,2) ,Union(2,3), Union(3,4), Union(4,5)……. Union(n-1,n)

The sequence of Union operations is called degenerate tree as below


lOMoAR cPSD| 29148908

Example : The union operation can be performed as follows.

union(10,20), union(20,30), union(30,40), union(40,50).

10 20 30 40 50 Initially

Union algorithm Time complexity : O ( n )

We can improve the performance of our union algorithm by avoiding the creation of degenerate trees.
We can use Weighted Union rule.
lOMoAR cPSD| 29148908

2.Weighted Union Algorithm


Definition : if the number of nodes in the tree with root i is less than the number in the tree with root j,
then make j the parent of i ; otherwise make i the parent of j.
Algorithm :
Algorithm : Weighted_Union( i, j )
{
p[i]  - count[i]; //Initially
p[j]  - count[j];
temp  p[i] + p[j];
if(p[i] > p[j]) then // i has few nodes than j
{
p[i] = j; // j becomes parent of I
p[j] = temp;
}
else
{
p[j] = i; // i becomes parent of j
p[i] = temp;
}
}
Example : Weighting rule to perform the sequence of set unions given below

1 2 3 4 -------------------------- n

Solution : Array Representation

i 1 2 3 4 n
----------------------------------
p -1 -1 -1 -1 -1

Step1 : Initially

1 2 3 4 ------------------------- n
lOMoAR cPSD| 29148908

Step2 : Union(1,2)
i 1 2 3 4 N
----------------------------------
p -2 1 -1 -1 -1

[ -2 ]
1 3 4 ------------------------ n

2
Step3 : Union(1,3)
i 1 2 3 4 n
----------------------------------
p -3 1 1 -1 -1

[ -3 ]
1 4 ------------------------ n

2 3 I = 1, j = 3 p[i]=-count[i]=p[1]=--2 p[j]=-count[j]=p[3]=-
Step4 : Union(1,4)

i 1 2 3 4 n
----------------------------------
p -4 1 1 1 -1
[-4]
1 ------------- n

2 3 4

Step4 : Union(1,n)

2 3 4 ---------------------------- n

The above trees obtained using the weighting rule


lOMoAR cPSD| 29148908

Example : Consider the behavior of Weighted union on the following sequences of unions.

Union ( 1,2 ), Union ( 3,4 ), Union ( 5,6 ), Union ( 7,8 ), Union ( 1,3 ), Union ( 5,7 ), Union ( 1,5 ),

Solution: The sequence of unions starting from the initial configuration p[i] = -count[i]=-1

[ -1 ] [ -1 ] [ -1 ] [ -1 ] [ -1 ] [ -1 ] [ -1 ] [ -1 ]

union(1,2) union(3,4) union(5,6) union(7,8)


[ -2 ] [ -2 ] [ -2 ] [ -2 ]

union ( 5,7 )
union ( 1,3 )

[ -4 ] [ -4 ]
lOMoAR cPSD| 29148908

union ( 1,5 )

[ -4 ] [ -4 ] [ -8 ]

Explanation in Weighted Union Algorithm


Union(1,5)
i 1 2 3 4 5 6 7 8
p -4 1 1 3 -4 5 5 7
i=1 and J=5
p[ i ]=-count[i]
p[1]=-count[1]
p[ 1 ] = -4
p[ j ]=-count[j]
p[5]=-count[5]
p[ 5 ] = -4
temp = p[ i ] + p [ j ]
temp = -4 – 4 = -8
if ( p[ i ] > p[ j ] ) then
-4 > -4 – false
p[ j ] = i, p[ 5 ] = 1 // for 5th node 1 is the root node
p[ i ] = temp
p[ 1 ] = -8
lOMoAR cPSD| 29148908

Find Algorithm : FIND(i), means it finds the root node of ith node, in other words, it returns the name of set i.

Algorithm SimpleFind(i)
{
while ( p[i] >= 0 ) do
i = p[i];
return i;
}
Example : Consider a tree

Solution : If we want to Find(i) = 8,


Array Representation of tree
i 1 2 3 4 5 6 7 8

p -8 1 1 3 1 5 5 7
i=8
while ( p[i]>=0) – true
i=p[8], i.e 7
while ( p[i]>=0) – true
i=p[7], i.e 5
while ( p[i]>=0) – true
i=p[5], i.e 1
while ( p[i]>=0) – false
return i, i.e i = 1
So 1 is the root node of node 8
Find algorithm Time complexity : O ( N2 )
lOMoAR cPSD| 29148908

Collapsing Find Algorithm :


Definition : if j is a node on the path from i to its root and a[i] # root[i], then set a[j] to root[i]. using
collapsing rule, the find operation can be performed.

Algorithm : Collapse_find( i )
{
// Problem Description : This algorithm Collapse all nodes from i to root node.
r = i;
while ( p[r] > 0 ) do
r := p[r]; //Find the root.
while ( i # r) do //Collapse nodes from i to root r
{
s =p[i];
p[i] =r;
i =s;
}
return r;
}

Example : Consider a tree


lOMoAR cPSD| 29148908

Solution : If we want to Find(i) = 8,


Array Representation of tree
i 1 2 3 4 5 6 7 8

p -8 1 1 3 1 5 5 7

Step1 : i = 8, r = 8
while ( p[r]>0) – true
r=p[8], i.e 7
while ( p[r]>0) – true
r=p[7], i.e 5
while ( p[r]>0) – true
r=p[5], i.e 1
while ( p[r]>0) – false
Step2 : Collapse nodes from I to root r.

while ( i # r )
8 # 1 – true
s=p[i],
s=p[8]
s=7
p[i]=r
p[8]=1 // means for 8th node 1 is the root node
i=7

again while ( i # r )
7 # 1 – true
s=p[i],
s=p[7]
s=5
p[i]=r
p[7]=1 // means for 7th node 1 is the root node
i=5

again while ( i # r )
5 # 1 – true
s=p[i],
s=p[5]
s=1
p[i]=r
p[5]=1 // means for 5th node 1 is the root node
i=1
lOMoAR cPSD| 29148908

again while ( i # r )
1 # 1 – false return r, i.e r=1

Array Representation of collapsing nodes from i to root j


i 1 2 3 4 5 6 7 8

p -8 1 1 3 1 5 1 1

After collapsing nodes from i to root

General Method:
In divide and conquer approach, a problem is divided into smaller problems, then the smaller
problems are solved independently, and finally the solutions of smaller problems are combined
into a solution for the large problem.
1. Divide the original problem into a set of subproblems.
2. Conquer: Solve every subproblem individually, recursively.
3. Combine: Put together the solutions of the subproblems to get the solution to the whole
problem.

Given a function to compute on ‘n’ inputs the divide-and-conquer strategy suggests splitting the inputs into ‘k’
distinct subsets, 1<k<=n, yielding ‘k’ sub problems.

 These sub problems must be solved, and then a method must be found to combine sub solutions into a
solution of the whole.
lOMoAR cPSD| 29148908

 If the sub problems are still relatively large, then the divide-and-conquer strategy can possibly be
reapplied.

 Often the sub problems resulting from a divide-and-conquer design are of the same type as the original
problem.

 For those cases the re application of the divide-and-conquer principle is naturally expressed by a
recursive algorithm.

 D And C(Algorithm) is initially invoked as D and C(P), where ‘p’ is the problem to be solved.

 Small(P) is a Boolean-valued function that determines whether the i/p size is small enough that the
answer can be computed without splitting
 If this so, the function ‘S’ is invoked.

 Otherwise, the problem P is divided into smaller sub problems.

 These sub problems P1, P2 …Pk are solved by recursive application of D And C.

 Combine is a function that determines the solution to p using the solutions to the ‘k’ sub problems.

 If the size of ‘p’ is n and the sizes of the ‘k’ sub problems are n1, n2 ….nk, respectively, then the
computing time of D And C is described by the recurrence relation.

f(n) is the time for dividing P & combining the solution to sub problems.

Algorithm D And C(P)


{
if small(P) then return S(P);
else
{
divide P into smaller instances P1, P2… Pk, k>=1;
Apply D And C to each of these sub problems;
return combine (D And C(P1), D And C(P2),…….,D And C(Pk));
}
}
lOMoAR cPSD| 29148908

Defective chessboard

GIVEN CONDITIONS:-
1.We have a chessboard of size n x n , where n =2k
2.Exactly one square is defective in the chessboard.
3.The tiles(trominoes) are in L-shape i.e. 3 squares.

Cover all the chessboard with L-shape tiles(trominoes), except the defective square.

As the size of the chessboard is n x n and n=2 k


• Therefore, Total no. of squares =2k x2k =22k
• No. of non-defective squares = 22k-1
lOMoAR cPSD| 29148908

• Now, for the value of K,22k-1 is divisible by 3.


• For E.g. K=1 , 22(1)-1 =3 is divisible by 3.
• K=2, 22(2) -1 =15 is divisible by 3.
Defective chessboards

1x1 2 x2 2 x2
2 x2 2 x2

As the Size of these chessboards displayed here, 1x1 and 2x2 we don’t have to place any L-shape tile in
the first and rest can be filled by just using 1 L-shaped tile.
For 4x 4 chessboard

8X8 DEFECTIVE CHESS BOARD


Step- 2 We divide the chess board into equal sub
Step-1 One of the cells is Defective half's.
lOMoAR cPSD| 29148908

Step-4 Again creation of defective boxes as we


Step- 3 Trick to cover the chess board with tiles divide the chess board

Creation of defective box DIVISION OF PROBLEM INTO SUB PROBLEM

Step-5 As we have finally divided the problem Step-6 The procedure will continue until all
into 2x2 board we will put the tiles. the sub board are covered with the tiles.
lOMoAR cPSD| 29148908

Step-7 The final chess board covered Step-7 Here we will cover the defectives
with all the titles and only left with the which we have created as in the last, there
defectives which we created. should be only one defective left.

COMBINIG OF ALL SUB PROBLEMS


lOMoAR cPSD| 29148908
lOMoAR cPSD| 29148908

Algorithm:TILING A DEFECTIVE CHESSBOARD

Algorithm TileBoard(topRow, topColumn, defectRow, defectColumn, size):


// top Row is row number of top-left corner of board.
// topColumn is column number of top-left corner of board.
// defectRow is row number of defective square.
// defectColumn is column number of defective square.
//size is length of one side of chessboard.
{
if (size = 1) return;
//Tile Selection
tileToUse := tile ++;
// Quadrant Size Calculation
quadrantSize := size / 2
//Tile top-left quadrant
if (defectRow < topRow + quadrantSize and defectColumn < topColumn + quadrantSize) then
//Defect is in this quadrant
TileBoard(topRow, topColumn, defectRow, defectColumn, quadrantSize)
lOMoAR cPSD| 29148908

else
{
// No defect in this quadrant
//Place a tile in bottom-right corner
board[topRow + quadrantSize - 1][topColumn + quadrantSize - 1] := tileToUse;
// Tile the rest
TileBoard (topRow, topColumn, topRow + quadrantSize, topColumn + quadrantSize - 1, quadrantSize)
//Code for remaining three quadrants is similar
TileBoard(topRow + quadrantSize, topColumn, topRow + quadrantSize, topColumn + quadrantSize,
quadrantSize)
TileBoard(topRow, topColumn + quadrantSize, topRow + quadrantSize - 1, topColumn + quadrantSize - 1,
quadrantSize)
TileBoard(topRow + quadrantSize, topColumn + quadrantSize, topRow + quadrantSize, topColumn +
quadrantSize, quadrantSize)
}
}
lOMoAR cPSD| 29148908

BINARY SEARCH:
Binary Search is a searching algorithm for finding an element's position in a sorted array. In this approach,
the element is always searched in the middle of a portion of an array.
Binary search can be implemented only on a sorted list of items. If the elements are not sorted already, we need
to sort them first.
Problem definition: Let ai, 1 ≤ i ≤ n be a list of elements that are sorted in non-decreasing order.The problem
is to find whether a given element x is present in the list or not. If x is present we have to determine a value j
(element’s position) such that aj=x. If x is not in the list, then j is set to zero.

Recursive binary search algorithm:


lOMoAR cPSD| 29148908
lOMoAR cPSD| 29148908

ANALYSIS:
In binary search the basic operation is key comparison. Binary Search can be analyzed with the best, worst, and
average case number of comparisons. The numbers of comparisons for the recursive and iterative versions of
Binary Search are the same, if comparison counting is relaxed slightly. For Recursive Binary Search, count each
pass through the if-then-else block as one comparison. For Iterative Binary Search, count each pass through the
while block as one comparison. Let us find out how many such key comparison does the algorithm make on an
array of n elements.
Best case – Θ(1) In the best case, the key is the middle in the array. A constant number of comparisons
(actually just 1) are required.
Worst case - Θ(log2 n) In the worst case, the key does not exist in the array at all. Through each recursion or
iteration of Binary Search, the size of the admissible range is halved. This halving can be done ceiling(log2n )
times. Thus, [ log2 n ] comparisons are required. Sometimes, in case of the successful search, it may take
lOMoAR cPSD| 29148908

maximum number of comparisons. [ log2 n ]. So worst case complexity of successful binary search is Θ (log2
n).
Average case - Θ (log2n) To find the average case, take the sum of the product of number of comparisons
required to find each element and the probability of searching for that element. To simplify the analysis, assume
that no item which is not in array will be searched for, and that the probabilities of searching for each element
are uniform.

Space Complexity –
The space requirements for the recursive and iterative versions of binary search are different.Iterative Binary
Search requires only a constant amount of space, while Recursive Binary Search requires space proportional to
the number of comparisons to maintain the recursion stack.

FINDING THE MAXIMUM AND MINIMUM

Max-Min problem is to find a maximum and minimum element from the given array. We can effectively solve
it using divide and conquer approach.
lOMoAR cPSD| 29148908

A simple and straight forward algorithm to achieve this is given below.

Explanation:
 Straight MaxMin requires 2(n-1) comparisons in the best, average & worst cases.
 By realizing the comparison of a[i]>max is false, improvement in a algorithm can be done. Hence we
can replace the contents of the for loop by,
 If(a[i]>Max) then Max = a[i]; Else if (a[i]<min) min=a[i]
 On the average a[i] is > max half the time. So, the avg. no. of comparison is 3n/2-1.

Algorithm based on Divide and Conquer strategy


Let P = (n, a [i],……,a [j]) denote an arbitrary instance of the problem. Here ‘n’ is the no. of elements in the list
(a[i],….,a[j]) and we are interested in finding the maximum and minimum of the list. If the list has more than 2
elements, P has to be divided into smaller instances.

For example, we might divide ‘P’ into the 2 instances,


P1= ( [n/2],a[1], a[n/2])
P2= (n-[n/2], a[[n/2]+1],……., a[n])
After having divided ‘P’ into 2 smaller sub problems, we can solve them by recursively invoking the same
divide-and-conquer algorithm.

Divide and conquer approach for Max. Min problem works in three stages.
 If a1 is the only element in the array, a1 is the maximum and minimum.
 If the array contains only two elements a1 and a2, then the single comparison between two elements can
decide the minimum and maximum of them.
 If there are more than two elements, the algorithm divides the array from the middle and creates two sub
problems. Both sub problems are treated as an independent problem and the same recursive process is
applied to them. This division continues until sub problem size becomes one or two.
lOMoAR cPSD| 29148908
lOMoAR cPSD| 29148908
lOMoAR cPSD| 29148908

Space Complexity:
Compared to the straight forward method, the MaxMin method requires extra stack space for i, j,
max, min, max1 and min1. Given n elements there will be [log2n] + 1 levels of recursion and we
need to save seven values for each recursive call. (6 + 1 for return address).
lOMoAR cPSD| 29148908

MERGE SORT
Merge sort is similar to the quick sort algorithm as it uses the divide and conquer approach to sort the elements.
It is one of the most popular and efficient sorting algorithm.
It divides the given list into two equal halves, calls itself for the two halves and then merges the two sorted
halves. We have to define the merge() function to perform the merging.
The sub-lists are divided again and again into halves until the list cannot be divided further. Then we combine
the pair of one element lists into two-element lists, sorting them in the process. The sorted two-element pairs is
merged into the four-element lists, and so on until we get the sorted list.
The time complexity of merge mort in the best case, worst case and average case is O(n log n)
and the number of comparisons used is nearly optimal.
Algorithm:

The merging of two sorted arrays can be done as follows.


Two pointers (array indices) are initialized to point to the first elements of the arrays
being merged.
The elements pointed to are compared, and the smaller of them is added to a new array
being constructed.
lOMoAR cPSD| 29148908

After that, the index of the smaller element is incremented to point to its immediate successor in
the array it was copied from. This operation is repeated until one of the two given arrays is
exhausted, and then the remaining elements of the other array are copied to the end of the new
array.

Example:
lOMoAR cPSD| 29148908

STRASSEN’S MATRIX MULTIPLICAION

Let A and B be the 2 n*n Matrix. The product matrix C=AB is calculated by using the formula,

C (i ,j )= A(i,k) B(k,j) for all ‘i’ and and j between 1 and n.


 The time complexity for the matrix Multiplication is O(n^3).

 Divide and conquer method suggest another way to compute the product of n*n matrix.

 We assume that N is a power of 2 .In the case N is not a power of 2 ,then enough rows and columns of zero
can be added to both A and B .SO that the resulting dimension are the powers of two.

 If n=2 then the following formula as a computed using a matrix multiplication operation for the elements of
A & B.

 If n>2,Then the elements are partitioned into sub matrix n/2*n/2..since ‘n’ is a power of 2 these product can
be recursively computed using the same formula .This Algorithm will continue applying itself to smaller sub
matrix until ‘N” become suitable small(n=2) so that the product is computed directly .
lOMoAR cPSD| 29148908

Divide and Conquer Following is simple Divide and Conquer method to multiply two square matrices.
1) Divide matrices A and B in 4 sub-matrices of size N/2 x N/2 as shown in the below diagram.
2) Calculate following values recursively. ae + bg, af + bh, ce + dg and cf + dh

Simple Divide and Conquer also leads to O(N3), can there be a better way?

In the above divide and conquer method, the main component for high time complexity is 8 recursive
calls. The idea of Strassen’s method is to reduce the number of recursive calls to 7. Strassen’s method is
similar to above simple divide and conquer method in the sense that this method also divides matrices to
sub-matrices of size N/2 x N/2 as shown in the above diagram, but in Strassen’s method, the four sub-
matrices of result are calculated using following formulae.
lOMoAR cPSD| 29148908

You might also like