Print the path between any two nodes of a tree | DFS
Given a tree of distinct nodes N with N-1 edges and a pair of nodes P. The task is to find and print the path between the two given nodes of the tree using DFS.
Input: N = 10 1 / \ 2 3 / | \ / | \ 4 5 6 7 8 9 Pair = {4, 8} Output: 4 -> 2 -> 1 -> 3 -> 8 Input: N = 3 1 / \ 2 3 Pair = {2, 3} Output: 2 -> 1 -> 3
For example, in the above tree the path between nodes 5 and 3 is 5 -> 2 -> 1 -> 3.
Path between nodes 4 and 8 is 4 -> 2 -> 1 -> 3 -> 8.
Approach:
Note: There should be a path between the given pair of nodes.
Below is the implementation of the above approach:
C++
// C++ implementation #include <bits/stdc++.h> using namespace std; // An utility function to add an edge in an // undirected graph. void addEdge(vector< int > v[], int x, int y) { v[x].push_back(y); v[y].push_back(x); } // A function to print the path between // the given pair of nodes. void printPath(vector< int > stack) { int i; for (i = 0; i < ( int )stack.size() - 1; i++) { cout << stack[i] << " -> " ; } cout << stack[i]; } // An utility function to do // DFS of graph recursively // from a given vertex x. void DFS(vector< int > v[], bool vis[], int x, int y, vector< int > stack) { stack.push_back(x); if (x == y) { // print the path and return on // reaching the destination node printPath(stack); return ; } vis[x] = true ; // if backtracking is taking place if (!v[x].empty()) { for ( int j = 0; j < v[x].size(); j++) { // if the node is not visited if (vis[v[x][j]] == false ) DFS(v, vis, v[x][j], y, stack); } } stack.pop_back(); } // A utility function to initialise // visited for the node and call // DFS function for a given vertex x. void DFSCall( int x, int y, vector< int > v[], int n, vector< int > stack) { // visited array bool vis[n + 1]; memset (vis, false , sizeof (vis)); // DFS function call DFS(v, vis, x, y, stack); } // Driver Code int main() { int n = 10; vector< int > v[n], stack; // Vertex numbers should be from 1 to 9. addEdge(v, 1, 2); addEdge(v, 1, 3); addEdge(v, 2, 4); addEdge(v, 2, 5); addEdge(v, 2, 6); addEdge(v, 3, 7); addEdge(v, 3, 8); addEdge(v, 3, 9); // Function Call DFSCall(4, 8, v, n, stack); return 0; } |
Java
// Java implementation of the above approach import java.util.*; class GFG { static Vector<Vector<Integer>> v = new Vector<Vector<Integer>>(); // An utility function to add an edge in an // undirected graph. static void addEdge( int x, int y){ v.get(x).add(y); v.get(y).add(x); } // A function to print the path between // the given pair of nodes. static void printPath(Vector<Integer> stack) { for ( int i = 0 ; i < stack.size() - 1 ; i++) { System.out.print(stack.get(i) + " -> " ); } System.out.println(stack.get(stack.size() - 1 )); } // An utility function to do // DFS of graph recursively // from a given vertex x. static void DFS( boolean vis[], int x, int y, Vector<Integer> stack) { stack.add(x); if (x == y) { // print the path and return on // reaching the destination node printPath(stack); return ; } vis[x] = true ; // if backtracking is taking place if (v.get(x).size() > 0 ) { for ( int j = 0 ; j < v.get(x).size(); j++) { // if the node is not visited if (vis[v.get(x).get(j)] == false ) { DFS(vis, v.get(x).get(j), y, stack); } } } stack.remove(stack.size() - 1 ); } // A utility function to initialise // visited for the node and call // DFS function for a given vertex x. static void DFSCall( int x, int y, int n, Vector<Integer> stack) { // visited array boolean vis[] = new boolean [n + 1 ]; Arrays.fill(vis, false ); // memset(vis, false, sizeof(vis)) // DFS function call DFS(vis, x, y, stack); } // Driver code public static void main(String[] args) { for ( int i = 0 ; i < 100 ; i++) { v.add( new Vector<Integer>()); } int n = 10 ; Vector<Integer> stack = new Vector<Integer>(); // Vertex numbers should be from 1 to 9. addEdge( 1 , 2 ); addEdge( 1 , 3 ); addEdge( 2 , 4 ); addEdge( 2 , 5 ); addEdge( 2 , 6 ); addEdge( 3 , 7 ); addEdge( 3 , 8 ); addEdge( 3 , 9 ); // Function Call DFSCall( 4 , 8 , n, stack); } } // This code is contributed by divyeshrabadiya07 |
Python3
# Python3 implementation of the above approach v = [[] for i in range ( 100 )] # An utility function to add an edge in an # undirected graph. def addEdge(x, y): v[x].append(y) v[y].append(x) # A function to print the path between # the given pair of nodes. def printPath(stack): for i in range ( len (stack) - 1 ): print (stack[i], end = " -> " ) print (stack[ - 1 ]) # An utility function to do # DFS of graph recursively # from a given vertex x. def DFS(vis, x, y, stack): stack.append(x) if (x = = y): # print the path and return on # reaching the destination node printPath(stack) return vis[x] = True # if backtracking is taking place if ( len (v[x]) > 0 ): for j in v[x]: # if the node is not visited if (vis[j] = = False ): DFS(vis, j, y, stack) del stack[ - 1 ] # A utility function to initialise # visited for the node and call # DFS function for a given vertex x. def DFSCall(x, y, n, stack): # visited array vis = [ 0 for i in range (n + 1 )] #memset(vis, false, sizeof(vis)) # DFS function call DFS(vis, x, y, stack) # Driver Code n = 10 stack = [] # Vertex numbers should be from 1 to 9. addEdge( 1 , 2 ) addEdge( 1 , 3 ) addEdge( 2 , 4 ) addEdge( 2 , 5 ) addEdge( 2 , 6 ) addEdge( 3 , 7 ) addEdge( 3 , 8 ) addEdge( 3 , 9 ) # Function Call DFSCall( 4 , 8 , n, stack) # This code is contributed by Mohit Kumar |
C#
// C# implementation of the above approach using System; using System.Collections; using System.Collections.Generic; class GFG { static List<List< int >> v = new List<List< int >>(); // An utility function to Add an edge in an // undirected graph. static void addEdge( int x, int y) { v[x].Add(y); v[y].Add(x); } // A function to print the path between // the given pair of nodes. static void printPath(List< int > stack) { for ( int i = 0; i < stack.Count - 1; i++) { Console.Write(stack[i] + " -> " ); } Console.WriteLine(stack[stack.Count - 1]); } // An utility function to do // DFS of graph recursively // from a given vertex x. static void DFS( bool []vis, int x, int y, List< int > stack) { stack.Add(x); if (x == y) { // print the path and return on // reaching the destination node printPath(stack); return ; } vis[x] = true ; // if backtracking is taking place if (v[x].Count > 0) { for ( int j = 0; j < v[x].Count; j++) { // if the node is not visited if (vis[v[x][j]] == false ) { DFS(vis, v[x][j], y, stack); } } } stack.RemoveAt(stack.Count - 1); } // A utility function to initialise // visited for the node and call // DFS function for a given vertex x. static void DFSCall( int x, int y, int n, List< int > stack) { // visited array bool []vis = new bool [n + 1]; Array.Fill(vis, false ); // memset(vis, false, sizeof(vis)) // DFS function call DFS(vis, x, y, stack); } // Driver code public static void Main( string [] args) { for ( int i = 0; i < 100; i++) { v.Add( new List< int >()); } int n = 10; List< int > stack = new List< int >(); // Vertex numbers should be from 1 to 9. addEdge(1, 2); addEdge(1, 3); addEdge(2, 4); addEdge(2, 5); addEdge(2, 6); addEdge(3, 7); addEdge(3, 8); addEdge(3, 9); // Function Call DFSCall(4, 8, n, stack); } } // This code is contributed by rutvik_56 |
Javascript
<script> // Javascript implementation of the above approach let v = []; // An utility function to add an edge in an // undirected graph. function addEdge(x, y) { v[x].push(y); v[y].push(x); } // A function to print the path between // the given pair of nodes. function printPath(stack) { for (let i = 0; i < stack.length - 1; i++) { document.write(stack[i] + " -> " ); } document.write(stack[stack.length - 1] + "<br>" ); } // An utility function to do // DFS of graph recursively // from a given vertex x. function DFS(vis, x, y, stack) { stack.push(x); if (x == y) { // Print the path and return on // reaching the destination node printPath(stack); return ; } vis[x] = true ; // If backtracking is taking place if (v[x].length > 0) { for (let j = 0; j < v[x].length; j++) { // If the node is not visited if (vis[v[x][j]] == false ) { DFS(vis, v[x][j], y, stack); } } } stack.pop(); } // A utility function to initialise // visited for the node and call // DFS function for a given vertex x. function DFSCall(x, y, n, stack) { // Visited array let vis = new Array(n + 1); for (let i = 0; i < (n + 1); i++) { vis[i] = false ; } // memset(vis, false, sizeof(vis)) // DFS function call DFS(vis, x, y, stack); } // Driver code for (let i = 0; i < 100; i++) { v.push([]); } let n = 10; let stack = []; // Vertex numbers should be from 1 to 9. addEdge(1, 2); addEdge(1, 3); addEdge(2, 4); addEdge(2, 5); addEdge(2, 6); addEdge(3, 7); addEdge(3, 8); addEdge(3, 9); // Function Call DFSCall(4, 8, n, stack); // This code is contributed by patel2127 </script> |
4 -> 2 -> 1 -> 3 -> 8
Efficient Approach :
In this approach we will utilise the concept of Lowest Common Ancestor (LCA).
1. We will find level and parent of every node using DFS.
2. We will find lowest common ancestor (LCA) of the two given nodes.
3. Starting from the first node we will travel to the LCA and keep on pushing
the intermediates nodes in our path vector.
4. Then, from the second node we will again travel to the LCA but this time
we will reverse the encountered intermediate nodes and then push them in
our path vector.
5. Finally, print the path vector to get the path between the two nodes.
C++
// C++ implementation for the above approach #include <bits/stdc++.h> using namespace std; // An utility function to add an edge in the tree void addEdge(vector< int > adj[], int x, int y) { adj[x].push_back(y); adj[y].push_back(x); } // running dfs to find level and parent of every node void dfs(vector< int > adj[], int node, int l, int p, int lvl[], int par[]) { lvl[node] = l; par[node] = p; for ( int child : adj[node]) { if (child != p) dfs(adj, child, l+1, node, lvl, par); } } int LCA( int a, int b, int par[], int lvl[]) { // if node a is at deeper level than // node b if (lvl[a] > lvl[b]) swap(a, b); // finding the difference in levels // of node a and b int diff = lvl[b] - lvl[a]; // moving b to the level of a while (diff != 0) { b = par[b]; diff--; } // means we have found the LCA if (a == b) return a; // finding the LCA while (a != b) a=par[a], b=par[b]; return a; } void printPath(vector< int > adj[], int a, int b, int n) { // stores level of every node int lvl[n+1]; // stores parent of every node int par[n+1]; // running dfs to find parent and level // of every node in the tree dfs(adj, 1, 0, -1, lvl, par); // finding the lowest common ancestor // of the nodes a and b int lca = LCA(a, b, par, lvl); // stores path between nodes a and b vector< int > path; // traversing the path from a to lca while (a != lca) path.push_back(a), a = par[a]; path.push_back(a); vector< int > temp; // traversing the path from b to lca while (b != lca) temp.push_back(b), b=par[b]; // reversing the path to get actual path reverse(temp.begin(), temp.end()); for ( int x : temp) path.push_back(x); // printing the path for ( int i = 0; i < path.size() - 1; i++) cout << path[i] << " -> " ; cout << path[path.size() - 1] << endl; } // Driver Code int main() { /* 1 / \ 2 7 / \ 3 6 / | \ 4 8 5 */ // number of nodes in the tree int n = 8; // adjacency list representation of the tree vector< int > adj[n+1]; addEdge(adj, 1, 2); addEdge(adj, 1, 7); addEdge(adj, 2, 3); addEdge(adj, 2, 6); addEdge(adj, 3, 4); addEdge(adj, 3, 8); addEdge(adj, 3, 5); // taking two input nodes // between which path is // to be printed int a = 4, b = 7; printPath(adj, a, b, n); return 0; } |
Java
import java.util.*; public class Main { public static void main(String[] args) { /* 1 / \ 2 7 / \ 3 6 / | \ 4 8 5 */ // number of nodes in the tree int n = 8 ; // adjacency list representation of the tree ArrayList<Integer>[] adj = new ArrayList[n + 1 ]; for ( int i = 0 ; i <= n; i++) { adj[i] = new ArrayList<>(); } addEdge(adj, 1 , 2 ); addEdge(adj, 1 , 7 ); addEdge(adj, 2 , 3 ); addEdge(adj, 2 , 6 ); addEdge(adj, 3 , 4 ); addEdge(adj, 3 , 8 ); addEdge(adj, 3 , 5 ); // taking two input nodes // between which path is // to be printed int a = 4 , b = 7 ; printPath(adj, a, b, n); } public static void addEdge(ArrayList<Integer>[] adj, int x, int y) { adj[x].add(y); adj[y].add(x); } // running dfs to find level and parent of every node public static void dfs(ArrayList<Integer>[] adj, int node, int l, int p, int [] lvl, int [] par) { lvl[node] = l; par[node] = p; for ( int child : adj[node]) { if (child != p) { dfs(adj, child, l + 1 , node, lvl, par); } } } public static int LCA( int a, int b, int [] par, int [] lvl) { // if node a is at deeper level than // node b if (lvl[a] > lvl[b]) { int temp = a; a = b; b = temp; } // finding the difference in levels // of node a and b int diff = lvl[b] - lvl[a]; // moving b to the level of a while (diff != 0 ) { b = par[b]; diff--; } // means we have found the LCA if (a == b) { return a; } // finding the LCA while (a != b) { a = par[a]; b = par[b]; } return a; } public static void printPath(ArrayList<Integer>[] adj, int a, int b, int n) { // stores level of every node int [] lvl = new int [n + 1 ]; // stores parent of every node int [] par = new int [n + 1 ]; // running dfs to find parent and level // of every node in the tree dfs(adj, 1 , 0 , - 1 , lvl, par); // finding the lowest common ancestor // of the nodes a and b int lca = LCA(a, b, par, lvl); ArrayList<Integer> path = new ArrayList<>(); // traversing the path from a to lca while (a != lca) { path.add(a); a = par[a]; } path.add(a); ArrayList<Integer> temp = new ArrayList<>(); // traversing the path from b to lca while (b != lca) { temp.add(b); b = par[b]; } // reversing the path to get actual path Collections.reverse(temp); path.addAll(temp); // printing the path for ( int i = 0 ; i < path.size() - 1 ; i++) { System.out.print(path.get(i) + " -> " ); } System.out.println(path.get(path.size() - 1 )); } } // This code is contributed by divyansh2212 |
Python3
from collections import defaultdict #An utility function to add an edge in the tree def add_edge(adj, x, y): adj[x].append(y) adj[y].append(x) # running dfs to find level and parent of every node def dfs(adj, node, l, p, lvl, par): lvl[node] = l par[node] = p # if node a is at deeper level than # node b for child in adj[node]: if child ! = p: dfs(adj, child, l + 1 , node, lvl, par) def LCA(a, b, par, lvl): if lvl[a] > lvl[b]: a, b = b, a # finding the difference in levels # of node a and b diff = lvl[b] - lvl[a] while diff ! = 0 : b = par[b] diff - = 1 if a = = b: return a while a ! = b: a = par[a] b = par[b] return a def print_path(adj, a, b, n): lvl = [ 0 ] * (n + 1 ) par = [ 0 ] * (n + 1 ) dfs(adj, 1 , 0 , - 1 , lvl, par) lca = LCA(a, b, par, lvl) path = [] while a ! = lca: path.append(a) a = par[a] path.append(a) temp = [] while b ! = lca: temp.append(b) b = par[b] temp.reverse() for x in temp: path.append(x) print ( " -> " .join( map ( str , path))) if __name__ = = "__main__" : n = 8 adj = defaultdict( list ) add_edge(adj, 1 , 2 ) add_edge(adj, 1 , 7 ) add_edge(adj, 2 , 3 ) add_edge(adj, 2 , 6 ) add_edge(adj, 3 , 4 ) add_edge(adj, 3 , 8 ) add_edge(adj, 3 , 5 ) # taking two input nodes # between which path is #to be printed a, b = 4 , 7 print_path(adj, a, b, n) |
Javascript
// Function to add an edge to an adjacency list function addEdge(adj, x, y) { adj[x].push(y); adj[y].push(x); } // Function to perform depth first search (DFS) traversal // and compute level and parent information for each node function dfs(adj, node, l, p, lvl, par) { lvl[node] = l; // set level of current node par[node] = p; // set parent of current node // Traverse through all adjacent nodes for (let i = 0; i < adj[node].length; i++) { let child = adj[node][i]; // If the adjacent node is not the parent of the current node, // perform DFS on the adjacent node if (child !== p) { dfs(adj, child, l + 1, node, lvl, par); } } } // Function to find the lowest common ancestor (LCA) of two nodes function LCA(a, b, par, lvl) { // Make sure that node a is at a lower level than node b if (lvl[a] > lvl[b]) { let temp = a; a = b; b = temp; } // Compute the difference in levels between node a and node b let diff = lvl[b] - lvl[a]; // Move up the tree from node b to reach the same level as node a while (diff !== 0) { b = par[b]; diff--; } // If node a and node b are the same, then they are the LCA if (a === b) { return a; } // Move up the tree from both nodes until they have the same parent while (a !== b) { a = par[a]; b = par[b]; } // The parent of the common ancestor is the LCA return a; } // Function to print the path between two nodes in a tree function printPath(adj, a, b, n) { // Initialize arrays to store level and parent information let lvl = new Array(n + 1).fill(0); let par = new Array(n + 1).fill(0); // Perform DFS traversal and compute level and parent information dfs(adj, 1, 0, -1, lvl, par); // Find the lowest common ancestor of nodes a and b let lca = LCA(a, b, par, lvl); // Initialize an array to store the path between nodes a and b let path = []; // Traverse from node a to the LCA and add all nodes to the path while (a !== lca) { path.push(a); a = par[a]; } // Add the LCA to the path path.push(a); // Initialize a temporary array to store the path from node b to the LCA let temp = []; // Traverse from node b to the LCA and add all nodes to the temporary array while (b !== lca) { temp.push(b); b = par[b]; } // Reverse the temporary array and add its elements to the path temp.reverse(); path.push(...temp); // Print the path for (let i = 0; i < path.length - 1; i++) { process.stdout.write(path[i] + " -> " ); } console.log(path[path.length - 1]); } let n = 8; let adj = new Array(n + 1); for (let i = 0; i <= n; i++) { adj[i] = []; } addEdge(adj, 1, 2); addEdge(adj, 1, 7); addEdge(adj, 2, 3); addEdge(adj, 2, 6); addEdge(adj, 3, 4); addEdge(adj, 3, 8); addEdge(adj, 3, 5); let a = 4, b = 7; printPath(adj, a, b, n); |
C#
using System; using System.Collections.Generic; using System.Linq; public class GFG { // An utility function to add an edge in the tree static void addEdge(List< int >[] adj, int x, int y) { adj[x].Add(y); adj[y].Add(x); } // running dfs to find level and parent of every node static void dfs(List< int >[] adj, int node, int l, int p, int [] lvl, int [] par) { lvl[node] = l; par[node] = p; foreach ( int child in adj[node]) { if (child != p) dfs(adj, child, l + 1, node, lvl, par); } } static int LCA( int a, int b, int [] par, int [] lvl) { // if node a is at deeper level than node b if (lvl[a] > lvl[b]) (a, b) = (b, a); // finding the difference in levels of node a and b int diff = lvl[b] - lvl[a]; // moving b to the level of a while (diff != 0) { b = par[b]; diff--; } // means we have found the LCA if (a == b) return a; // finding the LCA while (a != b) (a, b) = (par[a], par[b]); return a; } static void printPath(List< int >[] adj, int a, int b, int n) { // stores level of every node int [] lvl = new int [n + 1]; // stores parent of every node int [] par = new int [n + 1]; // running dfs to find parent and level // of every node in the tree dfs(adj, 1, 0, -1, lvl, par); // finding the lowest common ancestor // of the nodes a and b int lca = LCA(a, b, par, lvl); // stores path between nodes a and b List< int > path = new List< int >(); // traversing the path from a to lca while (a != lca) { path.Add(a); a = par[a]; } path.Add(a); List< int > temp = new List< int >(); // traversing the path from b to lca while (b != lca) { temp.Add(b); b = par[b]; } // reversing the path to get actual path temp.Reverse(); foreach ( int x in temp) path.Add(x); // printing the path for ( int i = 0; i < path.Count() - 1; i++) Console.Write(path[i] + " -> " ); Console.WriteLine(path[path.Count() - 1]); } // Driver Code static void Main() { /* 1 / \ 2 7 / \ 3 6 / | \ 4 8 5 */ // number of nodes in the tree int n = 8; // adjacency list representation of the tree List< int >[] adj = new List< int >[n + 1]; for ( int i = 0; i <= n; i++) { adj[i] = new List< int >(); } addEdge(adj, 1, 2); addEdge(adj, 1, 7); addEdge(adj, 2, 3); addEdge(adj, 2, 6); addEdge(adj, 3, 4); addEdge(adj, 3, 8); addEdge(adj, 3, 5); // taking two input nodes // between which path is // to be printed int a = 4, b = 7; printPath(adj, a, b, n); } } |
4 -> 3 -> 2 -> 1 -> 7
Time Complexity : O(N)
Space Complexity : O(N)
Contact Us