In the previous post, we introduced *union find algorithm* and used it to detect cycle in a graph. We used following *union()* and *find()* operations for subsets.

## CPP

`// Naive implementation of find` `int` `find(` `int` `parent[], ` `int` `i)` `{` ` ` `if` `(parent[i] == -1)` ` ` `return` `i;` ` ` `return` `find(parent, parent[i]);` `}` ` ` `// Naive implementation of union()` `void` `Union(` `int` `parent[], ` `int` `x, ` `int` `y)` `{` ` ` `int` `xset = find(parent, x);` ` ` `int` `yset = find(parent, y);` ` ` `parent[xset] = yset;` `}` |

*chevron_right*

*filter_none*

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 worst case scenario.

Let there be 4 elements 0, 1, 2, 3 Initially, all elements are single element subsets. 0 1 2 3 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)* 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)

Let us see the above example with union by rank Initially, all elements are single element subsets. 0 1 2 3 Do Union(0, 1) 1 2 3 / 0 Do Union(1, 2) 1 3 / \ 0 2 Do Union(2, 3) 1 / | \ 0 2 3

The second optimization to naive method is * Path Compression*. The idea is to flatten the tree when

*find()*is called. When

*find()*is called for an element x, root of the tree is returned. The

*find()*operation traverses up from x to find root. The idea of path compression is to make the found root as parent of x so that we don’t have to traverse all intermediate nodes again. If x is root of a subtree, then path (to root) from all nodes under x also compresses.

Let the subset {0, 1, .. 9} be represented as below and find() is called for element 3. 9 / | \ 4 5 6 / \ / \ 0 3 7 8 / \ 1 2 Whenfind()is called for 3, we traverse up and find 9 as representative of this subset. With path compression, we also make 3 as the child of 9 so that when find() is called next time for 1, 2 or 3, the path to root is reduced. 9 / / \ \ 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.

Following is union by rank and path compression based implementation to find a cycle in a graph.

## C++

`// A union by rank and path compression based program to` `// detect cycle in a graph` `#include <stdio.h>` `#include <stdlib.h>` `// a structure to represent an edge in the graph` `struct` `Edge {` ` ` `int` `src, dest;` `};` `// a structure to represent a graph` `struct` `Graph {` ` ` `// V-> Number of vertices, E-> Number of edges` ` ` `int` `V, E;` ` ` `// graph is represented as an array of edges` ` ` `struct` `Edge* edge;` `};` `struct` `subset {` ` ` `int` `parent;` ` ` `int` `rank;` `};` `// Creates a graph with V vertices and E edges` `struct` `Graph* createGraph(` `int` `V, ` `int` `E)` `{` ` ` `struct` `Graph* graph` ` ` `= (` `struct` `Graph*)` `malloc` `(` `sizeof` `(` `struct` `Graph));` ` ` `graph->V = V;` ` ` `graph->E = E;` ` ` `graph->edge = (` `struct` `Edge*)` `malloc` `(` ` ` `graph->E * ` `sizeof` `(` `struct` `Edge));` ` ` `return` `graph;` `}` `// A utility function to find set of an element i` `// (uses path compression technique)` `int` `find(` `struct` `subset subsets[], ` `int` `i)` `{` ` ` `// find root and make root as parent of i (path` ` ` `// compression)` ` ` `if` `(subsets[i].parent != i)` ` ` `subsets[i].parent` ` ` `= find(subsets, subsets[i].parent);` ` ` `return` `subsets[i].parent;` `}` `// A function that does union of two sets of x and y` `// (uses union by rank)` `void` `Union(` `struct` `subset subsets[], ` `int` `xroot, ` `int` `yroot)` `{` ` ` `// Attach smaller rank tree under root of high rank tree` ` ` `// (Union by Rank)` ` ` `if` `(subsets[xroot].rank < subsets[yroot].rank)` ` ` `subsets[xroot].parent = yroot;` ` ` `else` `if` `(subsets[xroot].rank > subsets[yroot].rank)` ` ` `subsets[yroot].parent = xroot;` ` ` `// If ranks are same, then make one as root and` ` ` `// increment its rank by one` ` ` `else` `{` ` ` `subsets[yroot].parent = xroot;` ` ` `subsets[xroot].rank++;` ` ` `}` `}` `// 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;` ` ` `// Allocate memory for creating V sets` ` ` `struct` `subset* subsets` ` ` `= (` `struct` `subset*)` `malloc` `(V * ` `sizeof` `(` `struct` `subset));` ` ` `for` `(` `int` `v = 0; v < V; ++v) {` ` ` `subsets[v].parent = v;` ` ` `subsets[v].rank = 0;` ` ` `}` ` ` `// Iterate through all edges of graph, find sets of both` ` ` `// vertices of every edge, if sets are same, then there` ` ` `// is cycle in graph.` ` ` `for` `(` `int` `e = 0; e < E; ++e) {` ` ` `int` `x = find(subsets, graph->edge[e].src);` ` ` `int` `y = find(subsets, graph->edge[e].dest);` ` ` `if` `(x == y)` ` ` `return` `1;` ` ` `Union(subsets, x, y);` ` ` `}` ` ` `return` `0;` `}` `// Driver code` `int` `main()` `{` ` ` `/* Let us create the following graph` ` ` `0` ` ` `| \` ` ` `| \` ` ` `1-----2 */` ` ` `int` `V = 3, E = 3;` ` ` `struct` `Graph* graph = createGraph(V, E);` ` ` `// add edge 0-1` ` ` `graph->edge[0].src = 0;` ` ` `graph->edge[0].dest = 1;` ` ` `// add edge 1-2` ` ` `graph->edge[1].src = 1;` ` ` `graph->edge[1].dest = 2;` ` ` `// add edge 0-2` ` ` `graph->edge[2].src = 0;` ` ` `graph->edge[2].dest = 2;` ` ` `if` `(isCycle(graph))` ` ` `printf` `(` `"Graph contains cycle"` `);` ` ` `else` ` ` `printf` `(` `"Graph doesn't contain cycle"` `);` ` ` `return` `0;` `}` |

*chevron_right*

*filter_none*

## Java

`// A union by rank and path compression` `// based program to detect cycle in a graph` `class` `Graph ` `{` ` ` `int` `V, E;` ` ` `Edge[] edge;` ` ` `Graph(` `int` `nV, ` `int` `nE)` ` ` `{` ` ` `V = nV;` ` ` `E = nE;` ` ` `edge = ` `new` `Edge[E];` ` ` `for` `(` `int` `i = ` `0` `; i < E; i++) ` ` ` `{` ` ` `edge[i] = ` `new` `Edge();` ` ` `}` ` ` `}` ` ` `// class to represent edge` ` ` `class` `Edge ` ` ` `{` ` ` `int` `src, dest;` ` ` `}` ` ` `// class to represent Subset` ` ` `class` `subset ` ` ` `{` ` ` `int` `parent;` ` ` `int` `rank;` ` ` `}` ` ` `// A utility function to find` ` ` `// set of an element i (uses` ` ` `// path compression technique)` ` ` `int` `find(subset[] subsets, ` `int` `i)` ` ` `{` ` ` `if` `(subsets[i].parent != i)` ` ` `subsets[i].parent` ` ` `= find(subsets, subsets[i].parent);` ` ` `return` `subsets[i].parent;` ` ` `}` ` ` `// A function that does union` ` ` `// of two sets of x and y` ` ` `// (uses union by rank)` ` ` `void` `Union(subset[] subsets, ` `int` `x, ` `int` `y)` ` ` `{` ` ` `int` `xroot = find(subsets, x);` ` ` `int` `yroot = find(subsets, y);` ` ` `if` `(subsets[xroot].rank < subsets[yroot].rank)` ` ` `subsets[xroot].parent = yroot;` ` ` `else` `if` `(subsets[yroot].rank < subsets[xroot].rank)` ` ` `subsets[yroot].parent = xroot;` ` ` `else` `{` ` ` `subsets[xroot].parent = yroot;` ` ` `subsets[yroot].rank++;` ` ` `}` ` ` `}` ` ` `// The main function to check whether` ` ` `// a given graph contains cycle or not` ` ` `int` `isCycle(Graph graph)` ` ` `{` ` ` `int` `V = graph.V;` ` ` `int` `E = graph.E;` ` ` `subset[] subsets = ` `new` `subset[V];` ` ` `for` `(` `int` `v = ` `0` `; v < V; v++) {` ` ` `subsets[v] = ` `new` `subset();` ` ` `subsets[v].parent = v;` ` ` `subsets[v].rank = ` `0` `;` ` ` `}` ` ` `for` `(` `int` `e = ` `0` `; e < E; e++) {` ` ` `int` `x = find(subsets, graph.edge[e].src);` ` ` `int` `y = find(subsets, graph.edge[e].dest);` ` ` `if` `(x == y)` ` ` `return` `1` `;` ` ` `Union(subsets, x, y);` ` ` `}` ` ` `return` `0` `;` ` ` `}` ` ` `// Driver Code` ` ` `public` `static` `void` `main(String[] args)` ` ` `{` ` ` `/* Let us create the following graph` ` ` `0` ` ` `| \` ` ` `| \` ` ` `1-----2 */` ` ` `int` `V = ` `3` `, E = ` `3` `;` ` ` `Graph graph = ` `new` `Graph(V, E);` ` ` `// add edge 0-1` ` ` `graph.edge[` `0` `].src = ` `0` `;` ` ` `graph.edge[` `0` `].dest = ` `1` `;` ` ` `// add edge 1-2` ` ` `graph.edge[` `1` `].src = ` `1` `;` ` ` `graph.edge[` `1` `].dest = ` `2` `;` ` ` `// add edge 0-2` ` ` `graph.edge[` `2` `].src = ` `0` `;` ` ` `graph.edge[` `2` `].dest = ` `2` `;` ` ` `if` `(graph.isCycle(graph) == ` `1` `)` ` ` `System.out.println(` `"Graph contains cycle"` `);` ` ` `else` ` ` `System.out.println(` ` ` `"Graph doesn't contain cycle"` `);` ` ` `}` `}` `// This code is contributed` `// by ashwani khemani` |

*chevron_right*

*filter_none*

## Python

`# A union by rank and path compression based` `# program to detect cycle in a graph` `from` `collections ` `import` `defaultdict` `# a structure to represent a graph` `class` `Graph:` ` ` `def` `__init__(` `self` `, num_of_v):` ` ` `self` `.num_of_v ` `=` `num_of_v` ` ` `self` `.edges ` `=` `defaultdict(` `list` `)` ` ` `# graph is represented as an` ` ` `# array of edges` ` ` `def` `add_edge(` `self` `, u, v):` ` ` `self` `.edges[u].append(v)` `class` `Subset:` ` ` `def` `__init__(` `self` `, parent, rank):` ` ` `self` `.parent ` `=` `parent` ` ` `self` `.rank ` `=` `rank` `# A utility function to find set of an element` `# node(uses path compression technique)` `def` `find(subsets, node):` ` ` `if` `subsets[node].parent !` `=` `node:` ` ` `subsets[node].parent ` `=` `find(subsets, subsets[node].parent)` ` ` `return` `subsets[node].parent` `# A function that does union of two sets` `# of u and v(uses union by rank)` `def` `union(subsets, u, v):` ` ` `# Attach smaller rank tree under root` ` ` `# of high rank tree(Union by Rank)` ` ` `if` `subsets[u].rank > subsets[v].rank:` ` ` `subsets[v].parent ` `=` `u` ` ` `elif` `subsets[v].rank > subsets[u].rank:` ` ` `subsets[u].parent ` `=` `v` ` ` `# If ranks are same, then make one as` ` ` `# root and increment its rank by one` ` ` `else` `:` ` ` `subsets[v].parent ` `=` `u` ` ` `subsets[u].rank ` `+` `=` `1` `# The main function to check whether a given` `# graph contains cycle or not` `def` `isCycle(graph):` ` ` `# Allocate memory for creating sets` ` ` `subsets ` `=` `[]` ` ` `for` `u ` `in` `range` `(graph.num_of_v):` ` ` `subsets.append(Subset(u, ` `0` `))` ` ` `# Iterate through all edges of graph,` ` ` `# find sets of both vertices of every` ` ` `# edge, if sets are same, then there` ` ` `# is cycle in graph.` ` ` `for` `u ` `in` `graph.edges:` ` ` `u_rep ` `=` `find(subsets, u)` ` ` `for` `v ` `in` `graph.edges[u]:` ` ` `v_rep ` `=` `find(subsets, v)` ` ` `if` `u_rep ` `=` `=` `v_rep:` ` ` `return` `True` ` ` `else` `:` ` ` `union(subsets, u_rep, v_rep)` `# Driver Code` `g ` `=` `Graph(` `3` `)` `# add edge 0-1` `g.add_edge(` `0` `, ` `1` `)` `# add edge 1-2` `g.add_edge(` `1` `, ` `2` `)` `# add edge 0-2` `g.add_edge(` `0` `, ` `2` `)` `if` `isCycle(g):` ` ` `print` `(` `'Graph contains cycle'` `)` `else` `:` ` ` `print` `(` `'Graph does not contain cycle'` `)` `# This code is contributed by` `# Sampath Kumar Surine` |

*chevron_right*

*filter_none*

## C#

`// A union by rank and path compression` `// based program to detect cycle in a graph` `using` `System;` `class` `Graph {` ` ` `public` `int` `V, E;` ` ` `public` `Edge[] edge;` ` ` `public` `Graph(` `int` `nV, ` `int` `nE)` ` ` `{` ` ` `V = nV;` ` ` `E = nE;` ` ` `edge = ` `new` `Edge[E];` ` ` `for` `(` `int` `i = 0; i < E; i++)` ` ` `{` ` ` `edge[i] = ` `new` `Edge();` ` ` `}` ` ` `}` ` ` `// class to represent edge` ` ` `public` `class` `Edge {` ` ` `public` `int` `src, dest;` ` ` `}` ` ` `// class to represent Subset` ` ` `class` `subset ` ` ` `{` ` ` `public` `int` `parent;` ` ` `public` `int` `rank;` ` ` `}` ` ` `// A utility function to find` ` ` `// set of an element i (uses` ` ` `// path compression technique)` ` ` `int` `find(subset[] subsets, ` `int` `i)` ` ` `{` ` ` `if` `(subsets[i].parent != i)` ` ` `subsets[i].parent` ` ` `= find(subsets, subsets[i].parent);` ` ` `return` `subsets[i].parent;` ` ` `}` ` ` `// A function that does union` ` ` `// of two sets of x and y` ` ` `// (uses union by rank)` ` ` `void` `Union(subset[] subsets, ` `int` `x, ` `int` `y)` ` ` `{` ` ` `int` `xroot = find(subsets, x);` ` ` `int` `yroot = find(subsets, y);` ` ` `if` `(subsets[xroot].rank < subsets[yroot].rank)` ` ` `subsets[xroot].parent = yroot;` ` ` `else` `if` `(subsets[yroot].rank < subsets[xroot].rank)` ` ` `subsets[yroot].parent = xroot;` ` ` `else` `{` ` ` `subsets[xroot].parent = yroot;` ` ` `subsets[yroot].rank++;` ` ` `}` ` ` `}` ` ` `// The main function to check whether` ` ` `// a given graph contains cycle or not` ` ` `int` `isCycle(Graph graph)` ` ` `{` ` ` `int` `V = graph.V;` ` ` `int` `E = graph.E;` ` ` `subset[] subsets = ` `new` `subset[V];` ` ` `for` `(` `int` `v = 0; v < V; v++) ` ` ` `{` ` ` `subsets[v] = ` `new` `subset();` ` ` `subsets[v].parent = v;` ` ` `subsets[v].rank = 0;` ` ` `}` ` ` `for` `(` `int` `e = 0; e < E; e++) ` ` ` `{` ` ` `int` `x = find(subsets, graph.edge[e].src);` ` ` `int` `y = find(subsets, graph.edge[e].dest);` ` ` `if` `(x == y)` ` ` `return` `1;` ` ` `Union(subsets, x, y);` ` ` `}` ` ` `return` `0;` ` ` `}` ` ` `// Driver Code` ` ` `static` `public` `void` `Main(String[] args)` ` ` `{` ` ` `/* Let us create the following graph` ` ` `0` ` ` `| \` ` ` `| \` ` ` `1-----2 */` ` ` `int` `V = 3, E = 3;` ` ` `Graph graph = ` `new` `Graph(V, E);` ` ` `// add edge 0-1` ` ` `graph.edge[0].src = 0;` ` ` `graph.edge[0].dest = 1;` ` ` `// add edge 1-2` ` ` `graph.edge[1].src = 1;` ` ` `graph.edge[1].dest = 2;` ` ` `// add edge 0-2` ` ` `graph.edge[2].src = 0;` ` ` `graph.edge[2].dest = 2;` ` ` `if` `(graph.isCycle(graph) == 1)` ` ` `Console.WriteLine(` `"Graph contains cycle"` `);` ` ` `else` ` ` `Console.WriteLine(` ` ` `"Graph doesn't contain cycle"` `);` ` ` `}` `}` `// This code is contributed` `// by Arnab Kundu` |

*chevron_right*

*filter_none*

**Output**

Graph contains cycle

**Related Articles : **

Union-Find Algorithm | Set 1 (Detect Cycle in a an Undirected Graph)

Disjoint Set Data Structures (Java Implementation)

Greedy Algorithms | Set 2 (Kruskal’s Minimum Spanning Tree Algorithm)

Job Sequencing Problem | Set 2 (Using Disjoint Set)

**References:**

http://en.wikipedia.org/wiki/Disjoint-set_data_structure

IITD Video Lecture

Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the **DSA Self Paced Course** at a student-friendly price and become industry ready.

## Recommended Posts:

- Union-Find Algorithm | (Union By Rank and Find by Optimized Path Compression)
- Disjoint Set Union on trees | Set 1
- Disjoint Set Union on trees | Set 2
- Disjoint Set (Or Union-Find) | Set 1 (Detect Cycle in an Undirected Graph)
- Dijkstra’s shortest path algorithm using set in STL
- Shortest path from source to destination such that edge weights along path are alternatively increasing and decreasing
- Extended Disjoint Set Union on Trees
- Program to find Circuit Rank of an Undirected Graph
- Implementation of Page Rank using Random Walk method in Python
- Dijkstra's shortest path algorithm | Greedy Algo-7
- Fleury's Algorithm for printing Eulerian Path or Circuit
- Printing Paths in Dijkstra's Shortest Path Algorithm
- Dijkstra's Shortest Path Algorithm using priority_queue of STL
- Java Program for Dijkstra's Algorithm with Path Printing
- Shortest Path Faster Algorithm
- Widest Path Problem | Practical application of Dijkstra's Algorithm
- D'Esopo-Pape Algorithm : Single Source Shortest Path
- Shortest path in a directed graph by Dijkstra’s algorithm
- Finding shortest path between any two nodes using Floyd Warshall Algorithm
- Applications of Dijkstra's shortest path algorithm