Skip to content
geeksforgeeks
  • Tutorials
    • Python
    • Java
    • Data Structures & Algorithms
    • ML & Data Science
    • Interview Corner
    • Programming Languages
    • Web Development
    • CS Subjects
    • DevOps And Linux
    • School Learning
    • Practice Coding Problems
  • Courses
    • DSA to Development
    • Get IBM Certification
    • Newly Launched!
      • Master Django Framework
      • Become AWS Certified
    • For Working Professionals
      • Interview 101: DSA & System Design
      • Data Science Training Program
      • JAVA Backend Development (Live)
      • DevOps Engineering (LIVE)
      • Data Structures & Algorithms in Python
    • For Students
      • Placement Preparation Course
      • Data Science (Live)
      • Data Structure & Algorithm-Self Paced (C++/JAVA)
      • Master Competitive Programming (Live)
      • Full Stack Development with React & Node JS (Live)
    • Full Stack Development
    • Data Science Program
    • All Courses
  • DSA
  • Interview Problems on Graph
  • Practice Graph
  • MCQs on Graph
  • Graph Tutorial
  • Graph Representation
  • Graph Properties
  • Types of Graphs
  • Graph Applications
  • BFS on Graph
  • DFS on Graph
  • Graph VS Tree
  • Transpose Graph
  • Dijkstra's Algorithm
  • Minimum Spanning Tree
  • Prim’s Algorithm
  • Topological Sorting
  • Floyd Warshall Algorithm
  • Strongly Connected Components
  • Advantages & Disadvantages
Open In App
Next Article:
Union-Find Algorithm | (Union By Rank and Find by Optimized Path Compression)
Next article icon

Union-Find Algorithm | (Union By Rank and Find by Optimized Path Compression)

Last Updated : 14 Dec, 2022
Comments
Improve
Suggest changes
Like Article
Like
Report

Check whether a given graph contains a cycle or not.

Example: 

Input: 

Union-Find Algorithm 1

Output: Graph contains Cycle.  Input: 

Union-Find Algorithm 2

Output: Graph does not contain Cycle.

Prerequisites: Disjoint Set (Or Union-Find), Union By Rank and Path Compression
We have already discussed union-find to detect cycle. Here we discuss find by path compression, where it is slightly modified to work faster than the original method as we are skipping one level each time we are going up the graph. Implementation of find function is iterative, so there is no overhead involved. Time complexity of optimized find function is O(log*(n)), i.e iterated logarithm, which converges to O(1) for repeated calls.
Refer this link for 
Proof of log*(n) complexity of Union-Find 

Explanation of find function: 

Take Example 1 to understand find function:
(1)call find(8) for first time and mappings will be done like this: 

Union-Find Algorithm 3


It took 3 mappings for find function to get the root of node 8. Mappings are illustrated below: 
From node 8, skipped node 7, Reached node 6. 
From node 6, skipped node 5, Reached node 4. 
From node 4, skipped node 2, Reached node 0.
(2)call find(8) for second time and mappings will be done like this: 
 

Union-Find Algorithm 4


It took 2 mappings to find function to get the root of node 8. Mappings are illustrated below: 
From node 8, skipped node 5, node 6, and node 7, Reached node 4. 
From node 4, skipped node 2, Reached node 0.
(3)call find(8) for third time and mappings will be done like this: 
 

Union-Find Algorithm 5

Finally, we see it took only 1 mapping for find function to get the root of node 8. Mappings are illustrated below: 
From node 8, skipped node 5, node 6, node 7, node 4, and node 2, Reached node 0. 
That is how it converges path from certain mappings to single mapping.

Explanation of example 1:

Initially array size and Arr look like:  Arr[9] = {0, 1, 2, 3, 4, 5, 6, 7, 8}  size[9] = {1, 1, 1, 1, 1, 1, 1, 1, 1} Consider the edges in the graph, and add them one by one to the disjoint-union set as follows:  Edge 1: 0-1  find(0)=>0, find(1)=>1, both have different root parent  Put these in single connected component as currently they doesn't belong to different connected components.  Arr[1]=0, size[0]=2; Edge 2: 0-2  find(0)=>0, find(2)=>2, both have different root parent  Arr[2]=0, size[0]=3; Edge 3: 1-3  find(1)=>0, find(3)=>3, both have different root parent  Arr[3]=0, size[0]=3; Edge 4: 3-4  find(3)=>1, find(4)=>4, both have different root parent  Arr[4]=0, size[0]=4; Edge 5: 2-4  find(2)=>0, find(4)=>0, both have same root parent  Hence, There is a cycle in graph.  We stop further checking for cycle in graph.   

Implementation:

C++
// CPP program to implement Union-Find with union // by rank and path compression. #include <bits/stdc++.h> using namespace std;  const int MAX_VERTEX = 101;  // Arr to represent parent of index i int Arr[MAX_VERTEX];  // Size to represent the number of nodes // in subgraph rooted at index i int size[MAX_VERTEX];  // set parent of every node to itself and // size of node to one void initialize(int n) {     for (int i = 0; i <= n; i++) {         Arr[i] = i;         size[i] = 1;     } }  // Each time we follow a path, find function // compresses it further until the path length // is greater than or equal to 1. int find(int i) {     // while we reach a node whose parent is     // equal to itself     while (Arr[i] != i)     {         Arr[i] = Arr[Arr[i]]; // Skip one level         i = Arr[i]; // Move to the new level     }     return i; }  // A function that does union of two nodes x and y // where xr is root node  of x and yr is root node of y void _union(int xr, int yr) {     if (size[xr] < size[yr]) // Make yr parent of xr     {         Arr[xr] = Arr[yr];         size[yr] += size[xr];     }     else // Make xr parent of yr     {         Arr[yr] = Arr[xr];         size[xr] += size[yr];     } }  // The main function to check whether a given // graph contains cycle or not int isCycle(vector<int> adj[], int V) {     // Iterate through all edges of graph, find     // nodes connecting them.     // If root nodes of both are same, then there is     // cycle in graph.     for (int i = 0; i < V; i++) {         for (int j = 0; j < adj[i].size(); j++) {             int x = find(i); // find root of i             int y = find(adj[i][j]); // find root of adj[i][j]              if (x == y)                 return 1; // If same parent             _union(x, y); // Make them connect         }     }     return 0; }  // Driver program to test above functions int main() {     int V = 3;      // Initialize the values for array Arr and Size     initialize(V);      /* Let us create following graph          0         |  \         |    \         1-----2 */      vector<int> adj[V]; // Adjacency list for graph      adj[0].push_back(1);     adj[0].push_back(2);     adj[1].push_back(2);      // call is_cycle to check if it contains cycle     if (isCycle(adj, V))         cout << "Graph contains Cycle.\n";     else         cout << "Graph does not contain Cycle.\n";      return 0; } 
Java
// Java program to implement Union-Find with union // by rank and path compression import java.util.*;  class GFG  { static int MAX_VERTEX = 101;  // Arr to represent parent of index i static int []Arr = new int[MAX_VERTEX];  // Size to represent the number of nodes // in subgraph rooted at index i static int []size = new int[MAX_VERTEX];  // set parent of every node to itself and // size of node to one static void initialize(int n) {     for (int i = 0; i <= n; i++)     {         Arr[i] = i;         size[i] = 1;     } }  // Each time we follow a path, find function // compresses it further until the path length // is greater than or equal to 1. static int find(int i) {     // while we reach a node whose parent is     // equal to itself     while (Arr[i] != i)     {         Arr[i] = Arr[Arr[i]]; // Skip one level         i = Arr[i]; // Move to the new level     }     return i; }  // A function that does union of two nodes x and y // where xr is root node of x and yr is root node of y static void _union(int xr, int yr) {     if (size[xr] < size[yr]) // Make yr parent of xr     {         Arr[xr] = Arr[yr];         size[yr] += size[xr];     }     else // Make xr parent of yr     {         Arr[yr] = Arr[xr];         size[xr] += size[yr];     } }  // The main function to check whether a given // graph contains cycle or not static int isCycle(Vector<Integer> adj[], int V) {     // Iterate through all edges of graph,      // find nodes connecting them.     // If root nodes of both are same,      // then there is cycle in graph.     for (int i = 0; i < V; i++)     {         for (int j = 0; j < adj[i].size(); j++)          {             int x = find(i); // find root of i                          // find root of adj[i][j]             int y = find(adj[i].get(j));               if (x == y)                 return 1; // If same parent             _union(x, y); // Make them connect         }     }     return 0; }  // Driver Code public static void main(String[] args)  {     int V = 3;      // Initialize the values for array Arr and Size     initialize(V);      /* Let us create following graph         0         | \         | \         1-----2 */      // Adjacency list for graph     Vector<Integer> []adj = new Vector[V];      for(int i = 0; i < V; i++)         adj[i] = new Vector<Integer>();      adj[0].add(1);     adj[0].add(2);     adj[1].add(2);      // call is_cycle to check if it contains cycle     if (isCycle(adj, V) == 1)         System.out.print("Graph contains Cycle.\n");     else         System.out.print("Graph does not contain Cycle.\n");     } }  // This code is contributed by PrinciRaj1992 
Python3
# Python3 program to implement Union-Find  # with union by rank and path compression.  # set parent of every node to itself  # and size of node to one  def initialize(n):     global Arr, size     for i in range(n + 1):         Arr[i] = i          size[i] = 1  # Each time we follow a path, find  # function compresses it further  # until the path length is greater  # than or equal to 1.  def find(i):     global Arr, size          # while we reach a node whose      # parent is equal to itself      while (Arr[i] != i):         Arr[i] = Arr[Arr[i]] # Skip one level          i = Arr[i] # Move to the new level     return i  # A function that does union of two  # nodes x and y where xr is root node  # of x and yr is root node of y  def _union(xr, yr):     global Arr, size     if (size[xr] < size[yr]): # Make yr parent of xr          Arr[xr] = Arr[yr]          size[yr] += size[xr]     else: # Make xr parent of yr         Arr[yr] = Arr[xr]          size[xr] += size[yr]  # The main function to check whether  # a given graph contains cycle or not  def isCycle(adj, V):     global Arr, size          # Iterate through all edges of graph,      # find nodes connecting them.      # If root nodes of both are same,      # then there is cycle in graph.     for i in range(V):         for j in range(len(adj[i])):             x = find(i) # find root of i              y = find(adj[i][j]) # find root of adj[i][j]               if (x == y):                 return 1 # If same parent              _union(x, y) # Make them connect     return 0  # Driver Code MAX_VERTEX = 101  # Arr to represent parent of index i  Arr = [None] * MAX_VERTEX   # Size to represent the number of nodes  # in subgraph rooted at index i  size = [None] * MAX_VERTEX   V = 3  # Initialize the values for array  # Arr and Size  initialize(V)   # Let us create following graph  #     0  # | \  # | \  # 1-----2   # Adjacency list for graph  adj = [[] for i in range(V)]   adj[0].append(1)  adj[0].append(2)  adj[1].append(2)   # call is_cycle to check if it  # contains cycle  if (isCycle(adj, V)):      print("Graph contains Cycle.")  else:     print("Graph does not contain Cycle.")  # This code is contributed by PranchalK 
C#
// C# program to implement Union-Find  // with union by rank and path compression using System; using System.Collections.Generic;      class GFG  { static int MAX_VERTEX = 101;  // Arr to represent parent of index i static int []Arr = new int[MAX_VERTEX];  // Size to represent the number of nodes // in subgraph rooted at index i static int []size = new int[MAX_VERTEX];  // set parent of every node to itself  // and size of node to one static void initialize(int n) {     for (int i = 0; i <= n; i++)     {         Arr[i] = i;         size[i] = 1;     } }  // Each time we follow a path,  // find function compresses it further  // until the path length is greater than  // or equal to 1. static int find(int i) {     // while we reach a node whose      // parent is equal to itself     while (Arr[i] != i)     {         Arr[i] = Arr[Arr[i]]; // Skip one level         i = Arr[i]; // Move to the new level     }     return i; }  // A function that does union of  // two nodes x and y where xr is  // root node of x and yr is root node of y static void _union(int xr, int yr) {     if (size[xr] < size[yr]) // Make yr parent of xr     {         Arr[xr] = Arr[yr];         size[yr] += size[xr];     }     else // Make xr parent of yr     {         Arr[yr] = Arr[xr];         size[xr] += size[yr];     } }  // The main function to check whether  // a given graph contains cycle or not static int isCycle(List<int> []adj, int V) {     // Iterate through all edges of graph,      // find nodes connecting them.     // If root nodes of both are same,      // then there is cycle in graph.     for (int i = 0; i < V; i++)     {         for (int j = 0; j < adj[i].Count; j++)          {             int x = find(i); // find root of i                          // find root of adj[i][j]             int y = find(adj[i][j]);               if (x == y)                 return 1; // If same parent             _union(x, y); // Make them connect         }     }     return 0; }  // Driver Code public static void Main(String[] args)  {     int V = 3;      // Initialize the values for      // array Arr and Size     initialize(V);      /* Let us create following graph         0         | \         | \         1-----2 */      // Adjacency list for graph     List<int> []adj = new List<int>[V];      for(int i = 0; i < V; i++)         adj[i] = new List<int>();      adj[0].Add(1);     adj[0].Add(2);     adj[1].Add(2);      // call is_cycle to check if it contains cycle     if (isCycle(adj, V) == 1)         Console.Write("Graph contains Cycle.\n");     else         Console.Write("Graph does not contain Cycle.\n");     } }  // This code is contributed by Rajput-Ji 
JavaScript
<script>  // Javascript program to implement Union-Find with union // by rank and path compression.  var MAX_VERTEX = 101;  // Arr to represent parent of index i var Arr = Array(MAX_VERTEX).fill(0);  // Size to represent the number of nodes // in subgraph rooted at index i var size = Array(MAX_VERTEX).fill(0);  // set parent of every node to itself and // size of node to one function initialize(n) {     for (var i = 0; i <= n; i++) {         Arr[i] = i;         size[i] = 1;     } }  // Each time we follow a path, find function // compresses it further until the path length // is greater than or equal to 1. function find(i) {     // while we reach a node whose parent is     // equal to itself     while (Arr[i] != i)     {         Arr[i] = Arr[Arr[i]]; // Skip one level         i = Arr[i]; // Move to the new level     }     return i; }  // A function that does union of two nodes x and y // where xr is root node  of x and yr is root node of y function _union(xr, yr) {     if (size[xr] < size[yr]) // Make yr parent of xr     {         Arr[xr] = Arr[yr];         size[yr] += size[xr];     }     else // Make xr parent of yr     {         Arr[yr] = Arr[xr];         size[xr] += size[yr];     } }  // The main function to check whether a given // graph contains cycle or not function isCycle(adj, V) {     // Iterate through all edges of graph, find     // nodes connecting them.     // If root nodes of both are same, then there is     // cycle in graph.     for (var i = 0; i < V; i++) {         for (var j = 0; j < adj[i].length; j++) {             var x = find(i); // find root of i             var y = find(adj[i][j]); // find root of adj[i][j]              if (x == y)                 return 1; // If same parent             _union(x, y); // Make them connect         }     }     return 0; }  // Driver program to test above functions var V = 3;  // Initialize the values for array Arr and Size initialize(V); /* Let us create following graph      0     |  \     |    \     1-----2 */ var adj = Array.from(Array(V), ()=>Array()); // Adjacency list for graph adj[0].push(1); adj[0].push(2); adj[1].push(2);  // call is_cycle to check if it contains cycle if (isCycle(adj, V))     document.write("Graph contains Cycle.<br>"); else     document.write("Graph does not contain Cycle.<br>");  // This code is contributed by rutvik_56. </script> 

Output
Graph contains Cycle.

Complexity Analysis:

  • Time Complexity(Find) : O(log*(n)) 
  • Time Complexity(union) : O(1)
  • Auxiliary Space: O(Max_Vertex)

Next Article
Union-Find Algorithm | (Union By Rank and Find by Optimized Path Compression)

A

Abhishek rajput
Improve
Article Tags :
  • Graph
  • Advanced Data Structure
  • Technical Scripter
  • Competitive Programming
  • DSA
  • union-find
Practice Tags :
  • Advanced Data Structure
  • Graph
  • union-find

Similar Reads

    Union By Rank and Path Compression in Union-Find Algorithm
    In the previous post, we introduced the Union-Find algorithm. We employed the union() and find() operations to manage subsets.Code Implementation:C++// Find the representative (root) of the // set that includes element i int Find(int i) { // If i itself is root or representative if (parent[i] == i)
    11 min read
    Disjoint Set Union (Randomized Algorithm)
    A Disjoint set union is an algorithm that is used to manage a collection of disjoint sets. A disjoint set is a set in which the elements are not in any other set. Also, known as union-find or merge-find.The disjoint set union algorithm allows you to perform the following operations efficiently:Find:
    15+ min read
    Introduction to Disjoint Set (Union-Find Algorithm)
    Two sets are called disjoint sets if they don't have any element in common. The disjoint set data structure is used to store such sets. It supports following operations:Merging two disjoint sets to a single set using Union operation.Finding representative of a disjoint set using Find operation.Check
    15+ min read
    Introduction to Divide and Conquer Algorithm
    Divide and Conquer Algorithm is a problem-solving technique used to solve problems by dividing the main problem into subproblems, solving them individually and then merging them to find solution to the original problem. Divide and Conquer is mainly useful when we divide a problem into independent su
    9 min read
    Extended Mo's Algorithm with ≈ O(1) time complexity
    Given an array of n elements and q range queries (range sum in this article) with no updates, task is to answer these queries with efficient time and space complexity. The time complexity of a range query after applying square root decomposition comes out to be O(?n). This square-root factor can be
    15+ min read
geeksforgeeks-footer-logo
Corporate & Communications Address:
A-143, 7th Floor, Sovereign Corporate Tower, Sector- 136, Noida, Uttar Pradesh (201305)
Registered Address:
K 061, Tower K, Gulshan Vivante Apartment, Sector 137, Noida, Gautam Buddh Nagar, Uttar Pradesh, 201305
GFG App on Play Store GFG App on App Store
Advertise with us
  • Company
  • About Us
  • Legal
  • Privacy Policy
  • In Media
  • Contact Us
  • Advertise with us
  • GFG Corporate Solution
  • Placement Training Program
  • Languages
  • Python
  • Java
  • C++
  • PHP
  • GoLang
  • SQL
  • R Language
  • Android Tutorial
  • Tutorials Archive
  • DSA
  • Data Structures
  • Algorithms
  • DSA for Beginners
  • Basic DSA Problems
  • DSA Roadmap
  • Top 100 DSA Interview Problems
  • DSA Roadmap by Sandeep Jain
  • All Cheat Sheets
  • Data Science & ML
  • Data Science With Python
  • Data Science For Beginner
  • Machine Learning
  • ML Maths
  • Data Visualisation
  • Pandas
  • NumPy
  • NLP
  • Deep Learning
  • Web Technologies
  • HTML
  • CSS
  • JavaScript
  • TypeScript
  • ReactJS
  • NextJS
  • Bootstrap
  • Web Design
  • Python Tutorial
  • Python Programming Examples
  • Python Projects
  • Python Tkinter
  • Python Web Scraping
  • OpenCV Tutorial
  • Python Interview Question
  • Django
  • Computer Science
  • Operating Systems
  • Computer Network
  • Database Management System
  • Software Engineering
  • Digital Logic Design
  • Engineering Maths
  • Software Development
  • Software Testing
  • DevOps
  • Git
  • Linux
  • AWS
  • Docker
  • Kubernetes
  • Azure
  • GCP
  • DevOps Roadmap
  • System Design
  • High Level Design
  • Low Level Design
  • UML Diagrams
  • Interview Guide
  • Design Patterns
  • OOAD
  • System Design Bootcamp
  • Interview Questions
  • Inteview Preparation
  • Competitive Programming
  • Top DS or Algo for CP
  • Company-Wise Recruitment Process
  • Company-Wise Preparation
  • Aptitude Preparation
  • Puzzles
  • School Subjects
  • Mathematics
  • Physics
  • Chemistry
  • Biology
  • Social Science
  • English Grammar
  • Commerce
  • World GK
  • GeeksforGeeks Videos
  • DSA
  • Python
  • Java
  • C++
  • Web Development
  • Data Science
  • CS Subjects
@GeeksforGeeks, Sanchhaya Education Private Limited, All rights reserved
We use cookies to ensure you have the best browsing experience on our website. By using our site, you acknowledge that you have read and understood our Cookie Policy & Privacy Policy
Lightbox
Improvement
Suggest Changes
Help us improve. Share your suggestions to enhance the article. Contribute your expertise and make a difference in the GeeksforGeeks portal.
geeksforgeeks-suggest-icon
Create Improvement
Enhance the article with your expertise. Contribute to the GeeksforGeeks community and help create better learning resources for all.
geeksforgeeks-improvement-icon
Suggest Changes
min 4 words, max Words Limit:1000

Thank You!

Your suggestions are valuable to us.

What kind of Experience do you want to share?

Interview Experiences
Admission Experiences
Career Journeys
Work Experiences
Campus Experiences
Competitive Exam Experiences