Open In App

Clone a Directed Acyclic Graph

Last Updated : 09 Mar, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

A directed acyclic graph (DAG) is a graph which doesn’t contain a cycle and has directed edges. We are given a DAG, we need to clone it, i.e., create another graph that has copy of its vertices and edges connecting them.

Examples:  

Input :
 
0 - - - > 1 - - - -> 4
|        /  \        ^   
|       /    \       |  
|      /      \      |
|     /        \     |  
|    /          \    |
|   /            \   |
v  v              v  |
2 - - - - - - - - -> 3


Output : Printing the output of the cloned graph gives: 
0-1
1-2
2-3
3-4
1-3
1-4
0-2

To clone a DAG without storing the graph itself within a hash (or dictionary in Python). To clone, it we basically do a depth-first traversal of the nodes, taking original node’s value and initializing new neighboring nodes with the same value, recursively doing, till the original graph is fully traversed. Below is the recursive approach to cloning a DAG (in Python). We make use of dynamic lists in Python, append operation to this list happens in constant time, hence, fast and efficient initialization of the graph.

Approach:

  • Initialize an empty hash map to keep track of the visited nodes and their clones.
  • Perform a DFS traversal of the original graph.
  • For each visited node, create a clone of the node and add it to the hash map.
  • For each outgoing edge of the visited node, check if the destination node is already in the hash map. If it is, add the corresponding clone to the clone of the visited node. If it is not, perform a DFS on the destination node and repeat the previous steps.
  • Once the DFS traversal is complete, return the clone of the starting node.

Implementation:

C++14




// C++ program to clone a directed acyclic graph.
#include <bits/stdc++.h>
using namespace std;
 
// Class to create a new graph node
class Node
{
    public:
        int key;
        vector<Node *> adj;
         
        // key is the value of the node
        // adj will be holding a dynamic
        // list of all Node type neighboring
        // nodes
        Node(int key)
        {
            this->key = key;
        }
};
 
// Function to print a graph,
// depth-wise, recursively
void printGraph(Node *startNode,
                vector<bool> &visited)
{
     
    // Visit only those nodes who have any
    // neighboring nodes to be traversed
    if (!startNode->adj.empty())
    {
         
        // Loop through the neighboring nodes
        // of this node. If source node not already
        // visited, print edge from source to
        // neighboring nodes. After visiting all
        // neighbors of source node, mark its visited
        // flag to true
        for(auto i : startNode->adj)
        {
            if (!visited[startNode->key])
            {
                cout << "edge " << startNode
                     << "-" << i
                     << ":" << startNode->key
                     << "-" << i->key
                     << endl;
                if (!visited[i->key])
                {
                    printGraph(i, visited);
                    visited[i->key] = true;
                }
            }
        }
    }
}
 
// Function to clone a graph. To do this, we
// start reading the original graph depth-wise,
// recursively. If we encounter an unvisited
// node in original graph, we initialize a
// new instance of Node for cloned graph with
// key of original node
Node *cloneGraph(Node *oldSource,
                 Node *newSource,
                 vector<bool> &visited)
{
    Node *clone = NULL;
     
    if (!visited[oldSource->key] &&
        !oldSource->adj.empty())
    {
        for(auto old : oldSource->adj)
        {
             
            // Below check is for backtracking, so new
            // nodes don't get initialized everytime
            if (clone == NULL ||
               (clone != NULL &&
               clone->key != old->key))
                clone = new Node(old->key);
                 
            newSource->adj.push_back(clone);
            cloneGraph(old, clone, visited);
             
            // Once, all neighbors for that particular node
            // are created in cloned graph, code backtracks
            // and exits from that node, mark the node as
            // visited in original graph, and traverse the
            // next unvisited
            visited[old->key] = true;
        }
    }
    return newSource;
}
 
// Driver Code
int main()
{
    Node *n0 = new Node(0);
    Node *n1 = new Node(1);
    Node *n2 = new Node(2);
    Node *n3 = new Node(3);
    Node *n4 = new Node(4);
     
    n0->adj.push_back(n1);
    n0->adj.push_back(n2);
    n1->adj.push_back(n2);
    n1->adj.push_back(n3);
    n1->adj.push_back(n4);
    n2->adj.push_back(n3);
    n3->adj.push_back(n4);
     
    // Flag to check if a node is already visited.
    // Stops indefinite looping during recursion
    vector<bool> visited(5, false);
    cout << "Graph Before Cloning:-\n";
    printGraph(n0, visited);
    visited = { false, false, false, false, false };
     
    cout << "\nGraph Before Starts:-\n";
    Node *clonedGraphHead = cloneGraph(
        n0, new Node(n0->key), visited);
    cout << "Cloning Process Completes.\n";
     
    visited = { false, false, false, false, false };
    cout << "\nGraph After Cloning:-\n";
    printGraph(clonedGraphHead, visited);
     
    return 0;
}
 
// This code is contributed by sanjeev2552


Java




// Java program to clone a directed acyclic graph.
import java.util.*;
 
class GFG{
 
// Class to create a new graph node
static class Node
{
    int key;
    ArrayList<Node> adj = new ArrayList<Node>();
     
    // key is the value of the node
    // adj will be holding a dynamic
    // list of all Node type neighboring
    // nodes
    Node(int key)
    {
        this.key = key;
    }
}
 
// Function to print a graph,
// depth-wise, recursively
static void printGraph(Node startNode,
                       boolean[] visited)
{
     
    // Visit only those nodes who have any
    // neighboring nodes to be traversed
    if (!startNode.adj.isEmpty())
    {
         
        // Loop through the neighboring nodes
        // of this node. If source node not already
        // visited, print edge from source to
        // neighboring nodes. After visiting all
        // neighbors of source node, mark its visited
        // flag to true
        for(Node i : startNode.adj)
        {
            if (!visited[startNode.key])
            {
                System.out.println("edge " + startNode +
                             "-" + i + ":" + startNode.key +
                             "-" + i.key);
                 
                if (!visited[i.key])
                {
                    printGraph(i, visited);
                    visited[i.key] = true;
                }
            }
        }
    }
}
 
// Function to clone a graph. To do this, we
// start reading the original graph depth-wise,
// recursively. If we encounter an unvisited
// node in original graph, we initialize a
// new instance of Node for cloned graph with
// key of original node
static Node cloneGraph(Node oldSource,
                       Node newSource,
                       boolean[] visited)
{
    Node clone = null;
     
    if (!visited[oldSource.key] &&
        !oldSource.adj.isEmpty())
    {
        for(Node old : oldSource.adj)
        {
             
            // Below check is for backtracking, so new
            // nodes don't get initialized everytime
            if (clone == null ||
               (clone != null &&
                clone.key != old.key))
                clone = new Node(old.key);
                 
            newSource.adj.add(clone);
            cloneGraph(old, clone, visited);
             
            // Once, all neighbors for that particular node
            // are created in cloned graph, code backtracks
            // and exits from that node, mark the node as
            // visited in original graph, and traverse the
            // next unvisited
            visited[old.key] = true;
        }
    }
    return newSource;
}
 
// Driver Code
public static void main(String[] args)
{
    Node n0 = new Node(0);
    Node n1 = new Node(1);
    Node n2 = new Node(2);
    Node n3 = new Node(3);
    Node n4 = new Node(4);
     
    n0.adj.add(n1);
    n0.adj.add(n2);
    n1.adj.add(n2);
    n1.adj.add(n3);
    n1.adj.add(n4);
    n2.adj.add(n3);
    n3.adj.add(n4);
     
    // Flag to check if a node is already visited.
    // Stops indefinite looping during recursion
    boolean visited[] = new boolean[5];
    System.out.println("Graph Before Cloning:-");
    printGraph(n0, visited);
    Arrays.fill(visited, false);
     
    System.out.println("\nCloning Process Starts");
    Node clonedGraphHead = cloneGraph(
        n0, new Node(n0.key), visited);
    System.out.println("Cloning Process Completes.");
     
    Arrays.fill(visited, false);
    System.out.println("\nGraph After Cloning:-");
    printGraph(clonedGraphHead, visited);
}
}
 
// This code is contributed by adityapande88


Python3




# Python program to clone a directed acyclic graph.
 
# Class to create a new graph node
class Node():
 
    # key is the value of the node
    # adj will be holding a dynamic
    # list of all Node type neighboring
    # nodes
    def __init__(self, key = None, adj = None):
        self.key = key
        self.adj = adj
 
# Function to print a graph, depth-wise, recursively
def printGraph(startNode, visited):
 
    # Visit only those nodes who have any
    # neighboring nodes to be traversed
    if startNode.adj is not None:
 
        # Loop through the neighboring nodes
        # of this node. If source node not already
        # visited, print edge from source to
        # neighboring nodes. After visiting all
        # neighbors of source node, mark its visited
        # flag to true
        for i in startNode.adj:
            if visited[startNode.key] == False :
                print("edge %s-%s:%s-%s"%(hex(id(startNode)), hex(id(i)), startNode.key, i.key))
                if visited[i.key] == False:
                    printGraph(i, visited)
                    visited[i.key] = True
 
# Function to clone a graph. To do this, we start
# reading the original graph depth-wise, recursively
# If we encounter an unvisited node in original graph,
# we initialize a new instance of Node for
# cloned graph with key of original node
def cloneGraph(oldSource, newSource, visited):
    clone = None
    if visited[oldSource.key] is False and oldSource.adj is not None:
        for old in oldSource.adj:
 
            # Below check is for backtracking, so new
            # nodes don't get initialized everytime
            if clone is None or(clone is not None and clone.key != old.key):
                clone = Node(old.key, [])
            newSource.adj.append(clone)
            cloneGraph(old, clone, visited)
 
            # Once, all neighbors for that particular node
            # are created in cloned graph, code backtracks
            # and exits from that node, mark the node as
            # visited in original graph, and traverse the
            # next unvisited
            visited[old.key] = True
    return newSource
 
# Creating DAG to be cloned
# In Python, we can do as many assignments of
# variables in one single line by using commas
n0, n1, n2 = Node(0, []), Node(1, []), Node(2, [])
n3, n4 = Node(3, []), Node(4)
n0.adj.append(n1)
n0.adj.append(n2)
n1.adj.append(n2)
n1.adj.append(n3)
n1.adj.append(n4)
n2.adj.append(n3)
n3.adj.append(n4)
 
# flag to check if a node is already visited.
# Stops indefinite looping during recursion
visited = [False]* (5)
print("Graph Before Cloning:-")
printGraph(n0, visited)
 
visited = [False]* (5)
print("\nCloning Process Starts")
clonedGraphHead = cloneGraph(n0, Node(n0.key, []), visited)
print("Cloning Process Completes.")
 
visited = [False]*(5)
print("\nGraph After Cloning:-")
printGraph(clonedGraphHead, visited)


Javascript




// Javascript program to clone a directed acyclic graph.
 
      // Class to create a new graph node
      class Node {
        constructor(key) {
          // key is the value of the node
          // adj will be holding a dynamic
          // list of all Node type neighboring
          // nodes
          this.key = key;
          this.adj = [];
        }
      }
 
      // Function to print a graph,
      // depth-wise, recursively
      function printGraph(startNode, visited) {
        // Visit only those nodes who have any
        // neighboring nodes to be traversed
 
        if (startNode.adj.length != 0) {
          // Loop through the neighboring nodes
          // of this node. If source node not already
          // visited, print edge from source to
          // neighboring nodes. After visiting all
          // neighbors of source node, mark its visited
          // flag to true
          for (i in startNode.adj) {
            if (!visited[startNode.key]) {
              console.log(
                "edge " +
                  startNode +
                  "-" +
                  startNode.adj[i] +
                  ":" +
                  startNode.key +
                  "-" +
                  startNode.adj[i].key
              );
 
              if (!visited[i.key]) {
                printGraph(startNode.adj[i], visited);
                visited[i.key] = true;
              }
            }
          }
        }
      }
 
      // Function to clone a graph. To do this, we
      // start reading the original graph depth-wise,
      // recursively. If we encounter an unvisited
      // node in original graph, we initialize a
      // new instance of Node for cloned graph with
      // key of original node
      function cloneGraph(oldSource, newSource, visited) {
        clone = null;
 
        if (!visited[oldSource.key] && !(oldSource.adj.length == 0)) {
          for (let old in oldSource.adj) {
            // Below check is for backtracking, so new
            // nodes don't get initialized everytime
            if (
              clone == null ||
              (clone != null && clone.key != oldSource.adj[old].key)
            )
              clone = new Node(oldSource.adj[old].key);
 
            newSource.adj.push(clone);
            cloneGraph(oldSource.adj[old], clone, visited);
 
            // Once, all neighbors for that particular node
            // are created in cloned graph, code backtracks
            // and exits from that node, mark the node as
            // visited in original graph, and traverse the
            // next unvisited
            visited[oldSource.adj[old].key] = true;
          }
        }
        return newSource;
      }
 
      // Driver Code
 
      n0 = new Node(0);
      n1 = new Node(1);
      n2 = new Node(2);
      n3 = new Node(3);
      n4 = new Node(4);
 
      n0.adj.push(n1);
      n0.adj.push(n2);
      n1.adj.push(n2);
      n1.adj.push(n3);
      n1.adj.push(n4);
      n2.adj.push(n3);
      n3.adj.push(n4);
 
      // Flag to check if a node is already visited.
      // Stops indefinite looping during recursion
 
      visited = [false, false, false, false, false];
      console.log("Graph Before Cloning:");
      printGraph(n0, visited);
      visited = [false, false, false, false, false];
 
      console.log("Graph Before Starts:");
      clonedGraphHead = cloneGraph(n0, new Node(n0.key), visited);
      console.log("Cloning Process Completes.");
 
      visited = [false, false, false, false, false];
      console.log("Graph After Cloning:");
      printGraph(clonedGraphHead, visited);


C#




using System;
using System.Collections.Generic;
 
class GFG
{
    class Node
    {
        public int Key { get; set; }
        public List<Node> Adj { get; set; }
 
        public Node(int key)
        {
            Key = key;
            Adj = new List<Node>();
        }
    }
 
    static void PrintGraph(Node startNode, bool[] visited)
    {
        if (startNode.Adj.Count > 0)
        {
            foreach (var i in startNode.Adj)
            {
                if (!visited[startNode.Key])
                {
                    Console.WriteLine("edge " + startNode + "-" + i + ":" + startNode.Key + "-" + i.Key);
 
                    if (!visited[i.Key])
                    {
                        PrintGraph(i, visited);
                        visited[i.Key] = true;
                    }
                }
            }
        }
    }
 
    static Node CloneGraph(Node oldSource, Node newSource, bool[] visited)
    {
        Node clone = null;
 
        if (!visited[oldSource.Key] && oldSource.Adj.Count > 0)
        {
            foreach (var old in oldSource.Adj)
            {
                if (clone == null || (clone != null && clone.Key != old.Key))
                    clone = new Node(old.Key);
 
                newSource.Adj.Add(clone);
                CloneGraph(old, clone, visited);
                visited[old.Key] = true;
            }
        }
 
        return newSource;
    }
 
    static void Main(string[] args)
    {
        var n0 = new Node(0);
        var n1 = new Node(1);
        var n2 = new Node(2);
        var n3 = new Node(3);
        var n4 = new Node(4);
 
        n0.Adj.Add(n1);
        n0.Adj.Add(n2);
        n1.Adj.Add(n2);
        n1.Adj.Add(n3);
        n1.Adj.Add(n4);
        n2.Adj.Add(n3);
        n3.Adj.Add(n4);
 
        bool[] visited = new bool[5];
        Console.WriteLine("Graph Before Cloning:-");
        PrintGraph(n0, visited);
        Array.Fill(visited, false);
 
        Console.WriteLine("\nCloning Process Starts");
        var clonedGraphHead = CloneGraph(n0, new Node(n0.Key), visited);
        Console.WriteLine("Cloning Process Completes.");
 
        Array.Fill(visited, false);
        Console.WriteLine("\nGraph After Cloning:-");
        PrintGraph(clonedGraphHead, visited);
    }
}
// this code is contributed by writer


Output

Graph Before Cloning:-
edge 0x1017e70-0x1017ea0:0-1
edge 0x1017ea0-0x1017ed0:1-2
edge 0x1017ed0-0x1017f00:2-3
edge 0x1017f00-0x1017f30:3-4
edge 0x1017ea0-0x1017f00:1-3
edge 0x1017ea0-0x1017f30:1-4
edge 0x1017e70-0x1017ed0:0-2

Graph Before Starts:-
Cloning Process Completes.

Graph After Cloning:-
edge 0x1019020-0x1019050:0-1
edge 0x1019050-0x10190a0:1-2
edge 0x10190a0-0x10190f0:2-3
edge 0x10190f0-0x1019140:3-4
edge 0x1019050-0x1019190:1-3
edge 0x1019050-0x10191e0:1-4
edge 0x1019020-0x1019240:0-2

Creating the DAG by appending adjacent edges to the vertex happens in O(1) time. Cloning of the graph takes O(E+V) time. 

Time Complexity : O(V+E)
Space Complexity : O(V+E)

Related Article: Clone an Undirected Graph



Previous Article
Next Article

Similar Reads

What is Directed Graph? | Directed Graph meaning
A directed graph is defined as a type of graph where the edges have a direction associated with them. Characteristics of Directed Graph Directed graphs have several characteristics that make them different from undirected graphs. Here are some key characteristics of directed graphs: Directed edges: In a directed graph, edges have a direction associ
3 min read
Assign directions to edges so that the directed graph remains acyclic
Given a graph with both directed and undirected edges. It is given that the directed edges don't form cycle. How to assign directions to undirected edges so that the graph (with all directed edges) remains acyclic even after the assignment? For example, in the below graph, blue edges don't have directions. We strongly recommend to minimize your bro
1 min read
Number of paths from source to destination in a directed acyclic graph
Given a Directed Acyclic Graph with n vertices and m edges. The task is to find the number of different paths that exist from a source vertex to destination vertex. Examples: Input: source = 0, destination = 4 Output: 3 Explanation: 0 -&gt; 2 -&gt; 3 -&gt; 4 0 -&gt; 3 -&gt; 4 0 -&gt; 4 Input: source = 0, destination = 1 Output: 1 Explanation: There
15+ min read
Longest path in a directed Acyclic graph | Dynamic Programming
Given a directed graph G with N vertices and M edges. The task is to find the length of the longest directed path in Graph.Note: Length of a directed path is the number of edges in it. Examples: Input: N = 4, M = 5 Output: 3 The directed path 1-&gt;3-&gt;2-&gt;4 Input: N = 5, M = 8 Output: 3 Simple Approach: A naive approach is to calculate the len
8 min read
Maximum difference between node and its ancestor in a Directed Acyclic Graph ( DAG )
Given a 2D array Edges[][], representing a directed edge between the pair of nodes in a Directed Acyclic Connected Graph consisting of N nodes valued from [1, N] and an array arr[] representing weights of each node, the task is to find the maximum absolute difference between the weights of any node and any of its ancestors. Examples: Input: N = 5,
8 min read
Count nodes with prime weight in a Directed Acyclic Graph
Given a directed acyclic graph (DAG) with N nodes with integer representations 0 to N-1 and an integer array arr[], where arr[i] is the parent of node i. The root of the DAG is node i if arr[i] is 0. The weight of a node is calculated as the sum of the node's value and the number of parent nodes it has, the task is to determine the number of nodes,
8 min read
Introduction to Directed Acyclic Graph
A Directed Acyclic Graph, often abbreviated as DAG, is a fundamental concept in graph theory. DAGs are used to show how things are related or depend on each other in a clear and organized way. In this article, we are going to learn about Directed Acyclic Graph, its properties, and application in real life. What is Directed Acyclic Graph?A Directed
3 min read
Shortest Path in Directed Acyclic Graph
Given a Weighted Directed Acyclic Graph and a source vertex in the graph, find the shortest paths from given source to all other vertices. Recommended PracticeShortest path from 1 to nTry It! For a general weighted graph, we can calculate single source shortest distances in O(VE) time using Bellman–Ford Algorithm. For a graph with no negative weigh
15 min read
All Topological Sorts of a Directed Acyclic Graph
Topological sorting for Directed Acyclic Graph (DAG) is a linear ordering of vertices such that for every directed edge uv, vertex u comes before v in the ordering. Topological Sorting for a graph is not possible if the graph is not a DAG. Given a DAG, print all topological sorts of the graph. For example, consider the below graph. All topological
11 min read
Longest Path in a Directed Acyclic Graph | Set 2
Given a Weighted Directed Acyclic Graph (DAG) and a source vertex in it, find the longest distances from source vertex to all other vertices in the given graph. We have already discussed how we can find Longest Path in Directed Acyclic Graph(DAG) in Set 1. In this post, we will discuss another interesting solution to find longest path of DAG that u
14 min read
Article Tags :
Practice Tags :
three90RightbarBannerImg