Open In App

Tree, Back, Edge and Cross Edges in DFS of Graph

Last Updated : 15 Feb, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Given a directed graph, the task is to identify tree, forward, back and cross edges present in the graph.

Note: There can be multiple answers.

Example:

Input: Graph

Output:
Tree Edges: 1->2, 2->4, 4->6, 1->3, 3->5, 5->7, 5->8
Forward Edges: 1->8
Back Edges: 6->2
Cross Edges: 5->4

  • Tree Edge: It is an edge which is present in the tree obtained after applying DFS on the graph. All the Green edges are tree edges. 
  • Forward Edge: It is an edge (u, v) such that v is a descendant but not part of the DFS tree. An edge from 1 to 8 is a forward edge. 
  • Back edge: It is an edge (u, v) such that v is the ancestor of node u but is not part of the DFS tree. Edge from 6 to 2 is a back edge. Presence of back edge indicates a cycle in directed graph
  • Cross Edge: It is an edge that connects two nodes such that they do not have any ancestor and a descendant relationship between them. The edge from node 5 to 4 is a cross edge.

Approach:

The idea is to perform a Depth-First Search (DFS) traversal of the directed graph while tracking discovery and finish times to classify edges into Tree, Forward, Back, and Cross edges based on their relationship with visited nodes and the DFS call stack.

Step by step approach:

  1. Initialize discovery and finish time arrays, a visited array, and an inStack array to track nodes in the current DFS recursion stack.
  2. Start DFS from each unvisited node, updating discovery times and marking nodes as visited and in the stack.
  3. If an adjacent node v is unvisited, classify the edge (u, v) as a Tree Edge and recursively call DFS on v.
  4. If v is already visited and present in the recursion stack, classify (u, v) as a Back Edge, indicating a cycle.
  5. If v is already visited but not in the recursion stack and discovery[u] < discovery[v], classify (u, v) as a Forward Edge, meaning v is a descendant of u.
  6. If v is already visited, not in the stack, and discovery[u] > discovery[v], classify (u, v) as a Cross Edge, indicating a connection between different DFS trees.
  7. After processing all neighbors of u, remove u from the stack and update its finish time.

Below is the implementation of the above approach:

C++
// c++ program to identify Tree, Back, 
// Edge and Cross Edges in DFS of Graph
#include <bits/stdc++.h>
using namespace std;

void dfs(int u, vector<vector<int>>& adj, vector<bool>& visited, 
    vector<bool>& inStack, vector<int>& discovery, 
    vector<int>& finish, int& timeStamp,
    vector<vector<vector<int>>>& edges) {
    
    visited[u] = true;
    inStack[u] = true;
    discovery[u] = ++timeStamp;
    
    for(int v : adj[u]) {
        if(!visited[v]) {
            
            // Tree Edge
            edges[0].push_back({u, v});
            dfs(v, adj, visited, inStack, 
            discovery, finish, timeStamp, edges);
        }
        else {
            if(inStack[v]) {
                
                // Back Edge
                edges[2].push_back({u, v});
            }
            else if(discovery[u] < discovery[v]) {
                
                // Forward Edge
                edges[1].push_back({u, v});
            }
            else {
                
                // Cross Edge
                edges[3].push_back({u, v});
            }
        }
    }
    
    inStack[u] = false;
    finish[u] = ++timeStamp;
}

vector<vector<vector<int>>> classifyEdges(vector<vector<int>>& adj) {
    int n = adj.size();
    
    // Array to store discovery timeStamp of node
    vector<int> discovery(n, 0);
    
    // Array to store finish timeStamp of node.
    vector<int> finish(n, 0);
    
    // Array to check if node is visited
    vector<bool> visited(n, false);
    
    // Array to check if node is in call stack.
    vector<bool> inStack(n, false);
    int timeStamp = 0;
    
    // Initialize result vector with 
    // 4 empty vectors for each edge type
    vector<vector<vector<int>>> edges(4);
    
    // Run DFS for each unvisited vertex
    for(int i = 0; i < n; i++) {
        if(!visited[i]) {
            dfs(i, adj, visited, inStack, 
            discovery, finish, timeStamp, edges);
        }
    }
    
    return edges;
}

int main() {
    
    vector<vector<int>> adj = {
        {1, 2, 7},     
        {3},     
        {4},       
        {5}, 
        {3, 6, 7},
        {1},
        {},
        {}
    };
    
    vector<vector<vector<int>>> edges = classifyEdges(adj);
    
    vector<string> edgeNames = {"Tree Edges", "Forward Edges", 
    "Back Edges", "Cross Edges"};
    
    for(int i = 0; i < 4; i++) {
        cout << edgeNames[i] << ": ";
        for(auto& edge : edges[i]) {
            cout << edge[0] << "->" << edge[1] << " ";
        }
        cout << endl;
    }
    
    return 0;
}
Java
// Java program to identify Tree, Back, 
// Edge and Cross Edges in DFS of Graph

import java.util.*;

class GfG {

    static void dfs(int u, int[][] adj, boolean[] visited, 
        boolean[] inStack, int[] discovery, int[] finish, 
        int[] timeStamp, List<int[]>[] edges) {
        
        visited[u] = true;
        inStack[u] = true;
        discovery[u] = ++timeStamp[0];
        
        for (int v : adj[u]) {
            if (!visited[v]) {
                
                // Tree Edge
                edges[0].add(new int[]{u, v});
                dfs(v, adj, visited, inStack, 
                discovery, finish, timeStamp, edges);
            } else {
                if (inStack[v]) {
                    
                    // Back Edge
                    edges[2].add(new int[]{u, v});
                } else if (discovery[u] < discovery[v]) {
                    
                    // Forward Edge
                    edges[1].add(new int[]{u, v});
                } else {
                    
                    // Cross Edge
                    edges[3].add(new int[]{u, v});
                }
            }
        }
        
        inStack[u] = false;
        finish[u] = ++timeStamp[0];
    }

    static List<int[]>[] classifyEdges(int[][] adj) {
        int n = adj.length;
        
        int[] discovery = new int[n];
        int[] finish = new int[n];
        boolean[] visited = new boolean[n];
        boolean[] inStack = new boolean[n];
        int[] timeStamp = {0};
        
        List<int[]>[] edges = new List[4];
        for (int i = 0; i < 4; i++) {
            edges[i] = new ArrayList<>();
        }
        
        for (int i = 0; i < n; i++) {
            if (!visited[i]) {
                dfs(i, adj, visited, inStack, discovery, finish, timeStamp, edges);
            }
        }
        
        return edges;
    }

    public static void main(String[] args) {
        int[][] adj = {
            {1, 2, 7},     
            {3},     
            {4},       
            {5}, 
            {3, 6, 7},
            {1},
            {},
            {}
        };
        
        List<int[]>[] edges = classifyEdges(adj);
        
        String[] edgeNames = {"Tree Edges", "Forward Edges", 
        "Back Edges", "Cross Edges"};
        
        for (int i = 0; i < 4; i++) {
            System.out.print(edgeNames[i] + ": ");
            for (int[] edge : edges[i]) {
                System.out.print(edge[0] + "->" + edge[1] + " ");
            }
            System.out.println();
        }
    }
}
Python
# Python program to identify Tree, Back, 
# Edge and Cross Edges in DFS of Graph

# Function to perform DFS
def dfs(u, adj, visited, inStack, discovery, finish, timeStamp, edges):
    visited[u] = True
    inStack[u] = True
    discovery[u] = timeStamp[0] = timeStamp[0] + 1
    
    for v in adj[u]:
        if not visited[v]:
            
            # Tree Edge
            edges[0].append([u, v])
            dfs(v, adj, visited, inStack, discovery, finish, timeStamp, edges)
        else:
            if inStack[v]:
                
                # Back Edge
                edges[2].append([u, v])
            elif discovery[u] < discovery[v]:
                
                # Forward Edge
                edges[1].append([u, v])
            else:
                
                # Cross Edge
                edges[3].append([u, v])
    
    inStack[u] = False
    finish[u] = timeStamp[0] = timeStamp[0] + 1

# Function to classify edges
def classifyEdges(adj):
    n = len(adj)
    
    discovery = [0] * n
    finish = [0] * n
    visited = [False] * n
    inStack = [False] * n
    timeStamp = [0]
    
    edges = [[] for _ in range(4)]
    
    for i in range(n):
        if not visited[i]:
            dfs(i, adj, visited, inStack, discovery, finish, timeStamp, edges)
    
    return edges

if __name__ == "__main__":
    adj = [
        [1, 2, 7],     
        [3],     
        [4],       
        [5], 
        [3, 6, 7],
        [1],
        [],
        []
    ]
    
    edges = classifyEdges(adj)
    
    edgeNames = ["Tree Edges", "Forward Edges", "Back Edges", "Cross Edges"]
    
    for i in range(4):
        print(edgeNames[i] + ":", end=" ")
        for edge in edges[i]:
            print(f"{edge[0]}->{edge[1]}", end=" ")
        print()
C#
// C# program to identify Tree, Back, 
// Edge and Cross Edges in DFS of Graph

using System;
using System.Collections.Generic;

class GfG {

    static void dfs(int u, int[][] adj, bool[] visited, 
        bool[] inStack, int[] discovery, int[] finish, 
        int[] timeStamp, List<int[]>[] edges) {
        
        visited[u] = true;
        inStack[u] = true;
        discovery[u] = ++timeStamp[0];
        
        foreach (int v in adj[u]) {
            if (!visited[v]) {
                
                // Tree Edge
                edges[0].Add(new int[]{u, v});
                dfs(v, adj, visited, inStack, 
                discovery, finish, timeStamp, edges);
            } else {
                if (inStack[v]) {
                    
                    // Back Edge
                    edges[2].Add(new int[]{u, v});
                } else if (discovery[u] < discovery[v]) {
                    
                    // Forward Edge
                    edges[1].Add(new int[]{u, v});
                } else {
                    
                    // Cross Edge
                    edges[3].Add(new int[]{u, v});
                }
            }
        }
        
        inStack[u] = false;
        finish[u] = ++timeStamp[0];
    }

    static List<int[]>[] classifyEdges(int[][] adj) {
        int n = adj.Length;
        
        int[] discovery = new int[n];
        int[] finish = new int[n];
        bool[] visited = new bool[n];
        bool[] inStack = new bool[n];
        int[] timeStamp = {0};
        
        List<int[]>[] edges = new List<int[]>[4];
        for (int i = 0; i < 4; i++) {
            edges[i] = new List<int[]>();
        }
        
        for (int i = 0; i < n; i++) {
            if (!visited[i]) {
                dfs(i, adj, visited, inStack, discovery, finish, timeStamp, edges);
            }
        }
        
        return edges;
    }

    static void Main() {
        int[][] adj = {
            new int[] {1, 2, 7},     
            new int[] {3},     
            new int[] {4},       
            new int[] {5}, 
            new int[] {3, 6, 7},
            new int[] {1},
            new int[] {},
            new int[] {}
        };
        
        List<int[]>[] edges = classifyEdges(adj);
        
        string[] edgeNames = {"Tree Edges", "Forward Edges", 
        "Back Edges", "Cross Edges"};
        
        for (int i = 0; i < 4; i++) {
            Console.Write(edgeNames[i] + ": ");
            foreach (var edge in edges[i]) {
                Console.Write(edge[0] + "->" + edge[1] + " ");
            }
            Console.WriteLine();
        }
    }
}
JavaScript
// JavaScript program to identify Tree, Back, 
// Edge and Cross Edges in DFS of Graph

function dfs(u, adj, visited, inStack, discovery, 
finish, timeStamp, edges) {
    visited[u] = true;
    inStack[u] = true;
    discovery[u] = ++timeStamp.value;

    for (let v of adj[u]) {
        if (!visited[v]) {
            
            // Tree Edge
            edges[0].push([u, v]);
            dfs(v, adj, visited, inStack, discovery, 
            finish, timeStamp, edges);
        } else {
            if (inStack[v]) {
                
                // Back Edge
                edges[2].push([u, v]);
            } else if (discovery[u] < discovery[v]) {
                
                // Forward Edge
                edges[1].push([u, v]);
            } else {
                
                // Cross Edge
                edges[3].push([u, v]);
            }
        }
    }

    inStack[u] = false;
    finish[u] = ++timeStamp.value;
}

function classifyEdges(adj) {
    let n = adj.length;
    
    // Array to store discovery timeStamp of node
    let discovery = new Array(n).fill(0);

    // Array to store finish timeStamp of node
    let finish = new Array(n).fill(0);

    // Array to check if node is visited
    let visited = new Array(n).fill(false);

    // Array to check if node is in call stack
    let inStack = new Array(n).fill(false);
    
    let timeStamp = { value: 0 };

    // Initialize result array with 4 
    // empty arrays for each edge type
    let edges = [[], [], [], []];

    // Run DFS for each unvisited vertex
    for (let i = 0; i < n; i++) {
        if (!visited[i]) {
            dfs(i, adj, visited, inStack, 
            discovery, finish, timeStamp, edges);
        }
    }

    return edges;
}

let adj = [
    [1, 2, 7],     
    [3],     
    [4],       
    [5], 
    [3, 6, 7],
    [1],
    [],
    []
];

let edges = classifyEdges(adj);

let edgeNames = ["Tree Edges", "Forward Edges", "Back Edges", "Cross Edges"];

for (let i = 0; i < 4; i++) {
    let result = edgeNames[i] + ": ";
    for (let edge of edges[i]) {
        result += edge[0] + "->" + edge[1] + " ";
    }
    console.log(result);
}

Output
Tree Edges: 0->1 1->3 3->5 0->2 2->4 4->6 4->7 
Forward Edges: 0->7 
Back Edges: 5->1 
Cross Edges: 4->3 

Time Complexity: O(V+E), where V is the number of nodes and E is the number of edges.
Auxiliary Space: O(V+E), due to recursive stack space, auxiliary arrays (discovery, finish, visited and inStack) and resultant array.



Next Article
Article Tags :
Practice Tags :

Similar Reads