Professional Documents
Culture Documents
Consider That There Are 5 Students in A Classroom Namely, A, B, C, D, E. They Will Be Denoted As 5 Different Subsets: (A), (B), (C), (D), (E)
Consider That There Are 5 Students in A Classroom Namely, A, B, C, D, E. They Will Be Denoted As 5 Different Subsets: (A), (B), (C), (D), (E)
A disjoint-set data structure is a data structure that keeps track of a set of elements
partitioned into a number of disjoint (non-overlapping) subsets.
For Example:
They will be denoted as 5 different subsets: {A}, {B}, {C}, {D}, {E}.
After some point of time, A became friends with B and C became friend with D. So,
A and B will now belong to same set and C and D will now belong to same set.
The disjoint data structure will now be: {A, B}, {C, D}, {E}.
If at any point in time, we want to check that if any two students are friends or not
then we can simply check if they belong to the same set or not.
• Union(A, B): This operation tells to merge the sets containing elements A and
B respectively by performing a Union operation on the sets.
• Find(A): This operation tells to find the subset to which the element A
belongs.
Implementation: The disjoint set data structure can be implemented using a Parent
array representation. If we are dealing with n items, i’th element of the array
represents the i’th item. More precisely, the i’th element of the array is the parent of
the i’th item.
For each edge, make subsets using both the vertices of the edge. If both the vertices
are in the same subset, a cycle is found.
Initially, all slots of parent array are initialized to -1 (means there is only one item in
every subset).
0 1 2
-1 -1 -1
• Edge 0-1: Find the subsets to which vertices 0 and 1 belongs to. Since they
are in different subsets, we take the union of them. For taking the union, either
make node 0 as the parent of node 1 or vice-versa.
return graph;
}
if (x == y)
return 1;
Union(parent, x, y);
}
return 0;
}
// Driver code
int main()
{
/* Let us create the following graph
0
|
|
1-----2 */
int V = 3, E = 3;
Graph* graph = createGraph(V, E);
if (isCycle(graph))
cout<<"graph contains cycle";
else
cout<<"graph doesn't contain cycle";
return 0;
}
Run
Java
class Graph
{
int V, E; // V-> no. of vertices & E->no.of edges
Edge edge[]; // /collection of all edges
class Edge
{
int src, dest;
};
if (x == y)
return 1;
graph.Union(parent, x, y);
}
return 0;
}
// Driver Method
public static void main (String[] args)
{
/* Let us create following graph
0
|
|
1-----2 */
int V = 3, E = 3;
Graph graph = new Graph(V, E);
if (graph.isCycle(graph)==1)
System.out.println( "graph contains cycle" );
else
System.out.println( "graph doesn't contain cycle" );
}
}
Run
Output:
graph contains cycle
Note that the implementation of union() and find() is naive and takes O(n) time in
worst case. These methods can be improved to O(Logn) using Union by Rank or
Height.
Union by Rank and Path Compression
In the previous post, we have introduced union find algorithm and used it to detect
cycle in a graph. We used following union() and find() operations for subsets.
The above union() and find() are naive and the worst case time complexity is linear.
The trees created to represent subsets can be skewed and can become like a linked
list. Following is an example of the worst case scenario.
Do Union(0, 1)
1 2 3
/
0
Do Union(1, 2)
2 3
/
1
/
0
Do Union(2, 3)
3
/
2
/
1
/
0
The above operations can be optimized to O(Log n) time complexity in worst case.
The idea is to always attach smaller depth tree under the root of the deeper tree.
This technique is called union by rank. The term rank is preferred instead of height
because if path compression technique (we have discussed it below) is used,
then rank is not always equal to height. Also, size (in place of height) of trees can
also be used as rank. Using size as rank also yields worst case time complexity as
O(Logn) (See this for proof)
Do Union(0, 1)
1 2 3
/
0
Do Union(1, 2)
1 3
/
0 2
Do Union(2, 3)
1
/ |
0 2 3
for element 3.
/ |
4 5 6
/ /
0 3 7 8
1 2
that when find() is called next time for 1, 2 or 3, the path to root is red
uced.
/ /
4 5 6 3
/ / /
0 7 8 1 2
The two techniques complement each other. The time complexity of each operation
becomes even smaller than O(Logn). In fact, amortized time complexity effectively
becomes small constant.
#include <stdio.h>
#include <stdlib.h>
// a structure to represent an edge in the graph
struct Edge {
int src, dest;
};
struct subset {
int parent;
int rank;
};
return graph;
}
return subsets[i].parent;
}
// The main function to check whether a given graph contains cycle or not
int isCycle(struct Graph* graph)
{
int V = graph->V;
int E = graph->E;
if (x == y)
return 1;
Union(subsets, x, y);
}
return 0;
}
// Driver program to test above functions
int main()
{
/* Let us create the following graph
0
|
|
1-----2 */
int V = 3, E = 3;
struct Graph* graph = createGraph(V, E);
if (isCycle(graph))
printf("Graph contains cycle");
else
printf("Graph doesn't contain cycle");
return 0;
}
Run
Java
Output:
Graph contains cycle
Kruskal’s Minimum Spanning Tree Algorithm
What is Minimum Spanning Tree?
Given a connected and undirected graph, a spanning tree of that graph is a
subgraph that is a tree and connects all the vertices together. A single graph can
have many different spanning trees. A minimum spanning tree (MST) or minimum
weight spanning tree for a weighted, connected and undirected graph is a spanning
tree with weight less than or equal to the weight of every other spanning tree. The
weight of a spanning tree is the sum of weights given to each edge of the spanning
tree.
Algorithm: The Kruskal's algorithm for finding MST works on a Greedy method.
1. Sort all the edges of the given graph in increasing order according to their
weight.
2. Pick the smallest edge. Check if it forms a cycle with the spanning tree formed
so far. If cycle is not formed, include this edge. Else, discard it.
3. Repeat step 2 until there are (V-1) edges in the spanning tree.
Note: In Step 2 to check if adding an edge forms a cycle or not efficiently, Union-
Find algorithm is used.
The graph contains 9 vertices and 14 edges. So, the minimum spanning tree formed
will be having (9 - 1) = 8 edges.
After sorting:
Weight Src Dest
1 7 6
2 8 2
2 6 5
4 0 1
4 2 5
6 8 6
7 2 3
7 7 8
8 0 7
8 1 2
9 3 4
10 5 4
11 1 7
14 3 5
Now pick all edges one by one from sorted list of edges:
1. Pick edge 7-6: No cycle is formed, include it.
6. Pick edge 8-6: Since including this edge results in cycle, discard it.
7. Pick edge 2-3: No cycle is formed, include it.
8. Pick edge 7-8: Since including this edge results in cycle, discard it.
9. Pick edge 0-7: No cycle is formed, include it.
10. Pick edge 1-2: Since including this edge results in cycle, discard it.
11. Pick edge 3-4: No cycle is formed, include it.
Since the number of edges included equals (V - 1), the algorithm stops here.
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
return node;
}
return minCost;
}
// Driver Code
int main()
{
/* Let us create following weighted graph
10
0--------1
||
6| 5 |15
||
2--------3
4 */
int V = 4; // Number of vertices in graph
int E = 5; // Number of edges in graph
return 0;
}
Run
Java
import java.util.Arrays;
@Override
public int compareTo(Edge o) {
if(this.weight > o.weight)
return 1;
return -1;
}
}
class GFG {
return node;
}
// Driver code
public static void main(String[] args)
{
/* Let us create following weighted graph
10
0--------1
||
6| 5 |15
||
2--------3
4 */
int V = 4; // Number of vertices in graph
int E = 5; // Number of edges in graph
Output:
The cost of MST is: 19