Depth-First Search (DFS) is a basic algorithm used to explore graph structures. In directed graphs, DFS can start from a specific point and explore all the connected nodes. It can also be used to make sure every part of the graph is visited, even if the graph has disconnected sections. This article explains how DFS works when starting from a single point and how it can be used to explore an entire graph, including disconnected parts.
Move to 0: Mark as visited. Output: 0 (backtrack to 2)
Move to 3: Mark as visited. Output: 3 (backtrack to 2)
All neighbors of 2 explored (backtrack to 1)
All neighbors of 1 explored (end of traversal)
Input: V = 5, E = 4, edges = {{0, 2}, {0, 3}, {2, 4}, {1, 0}}, source = 2
Output: 2 4 Explanation: DFS Steps:
Start at 2: Mark as visited. Output: 2
Move to 4: Mark as visited. Output: 4 (backtrack to 2)
All neighbors of 2 explored (backtrack to start)
DFS from a Given Source in Directed Graph
Depth-First Search (DFS) from a given source is a method of exploring a directed graph by starting at a specific vertex and traversing each node as far as we can go down in the path. If we reach a vertex that has no unvisited neighbors, we backtrack to the previous vertex to explore any other paths that haven't been visited yet. This approach is particularly useful for tasks such as finding paths, checking connectivity, and exploring all reachable nodes from a starting point.
How It Works:
Keep a boolean visited array to keep track of which vertices have already been visited. This will help in not entering in infinite loops when there are cycles in the graph.
Use Recursion to visited all unvisited neighbours of source node:
First marks the current vertex as visited and processes the current vertex (for example, by printing its value).
Then, recursively visits each unvisited neighbor of the current vertex.
If a vertex has no unvisited neighbors, backtracks to the previous vertex to explore other unvisited paths.
Below is the implementation of the above approach:
C++
#include<bits/stdc++.h>usingnamespacestd;// Function to add an edge to the adjacency listvoidaddEdge(vector<vector<int>>&adj,ints,intt){// Add edge from vertex s to tadj[s].push_back(t);}// Recursive function for DFS traversalvoidDFSRec(vector<vector<int>>&adj,vector<bool>&visited,ints){// Mark the current vertex as visitedvisited[s]=true;// Print the current vertexcout<<s<<" ";// Recursively visit all adjacent vertices that are not visited yetfor(inti:adj[s])if(visited[i]==false)DFSRec(adj,visited,i);}// Main DFS function that initializes the visited array// and call DFSRecvoidDFS(vector<vector<int>>&adj,ints){vector<bool>visited(adj.size(),false);// Call the recursive DFS functionDFSRec(adj,visited,s);}intmain(){intV=5;// Create an adjacency list for the graphvector<vector<int>>adj(V);// Define the edges of the graphvector<vector<int>>edges={{1,2},{1,0},{2,0},{2,3},{4,2}};// Populate the adjacency list with edgesfor(auto&e:edges)addEdge(adj,e[0],e[1]);intsource=1;cout<<"DFS from source: "<<source<<endl;DFS(adj,source);return0;}
C
#include<stdio.h>#include<stdlib.h>// Node structure for adjacency liststructNode{intdest;structNode*next;};// Structure to represent an adjacency liststructAdjList{structNode*head;};// Function to create a new adjacency list nodestructNode*createNode(intdest){structNode*newNode=(structNode*)malloc(sizeof(structNode));newNode->dest=dest;newNode->next=NULL;returnnewNode;}// Function to add an edge to the adjacency listvoidaddEdge(structAdjListadj[],ints,intt){// Add edge from s to tstructNode*newNode=createNode(t);newNode->next=adj[s].head;adj[s].head=newNode;}// Recursive function for DFS traversalvoidDFSRec(structAdjListadj[],intvisited[],ints){// Mark the current vertex as visitedvisited[s]=1;// Print the current vertexprintf("%d ",s);// Traverse all adjacent vertices that are not visited yetstructNode*current=adj[s].head;while(current!=NULL){intdest=current->dest;if(!visited[dest]){DFSRec(adj,visited,dest);}current=current->next;}}// Main DFS function that initializes the visited array// and calls DFSRecvoidDFS(structAdjListadj[],intV,ints){// Initialize visited array to falseintvisited[5]={0};DFSRec(adj,visited,s);}intmain(){intV=5;// Create an array of adjacency listsstructAdjListadj[V];// Initialize each adjacency list as emptyfor(inti=0;i<V;i++){adj[i].head=NULL;}intE=5;// Define the edges of the graphintedges[][2]={{1,2},{1,0},{2,0},{2,3},{2,4}};// Populate the adjacency list with edgesfor(inti=0;i<E;i++){addEdge(adj,edges[i][0],edges[i][1]);}intsource=1;printf("DFS from source: %d\n",source);DFS(adj,V,source);return0;}
Java
importjava.util.ArrayList;importjava.util.List;classGfG{// Function to add an edge to the adjacency liststaticvoidaddEdge(List<List<Integer>>adj,ints,intt){// Add edge from vertex s to tadj.get(s).add(t);}// Recursive function for DFS traversalstaticvoidDFSRec(List<List<Integer>>adj,boolean[]visited,ints){// Mark the current vertex as visitedvisited[s]=true;// Print the current vertexSystem.out.print(s+" ");// Recursively visit all adjacent vertices that are// not visited yetfor(inti:adj.get(s)){if(!visited[i]){DFSRec(adj,visited,i);}}}// Main DFS function that initializes the visited arraystaticvoidDFS(List<List<Integer>>adj,ints){boolean[]visited=newboolean[adj.size()];// Call the recursive DFS functionDFSRec(adj,visited,s);}publicstaticvoidmain(String[]args){intV=5;// Number of vertices in the graph// Create an adjacency list for the graphList<List<Integer>>adj=newArrayList<>(V);for(inti=0;i<V;i++){adj.add(newArrayList<>());}// Define the edges of the graphint[][]edges={{1,2},{1,0},{2,0},{2,3},{2,4}};// Populate the adjacency list with edgesfor(int[]e:edges){addEdge(adj,e[0],e[1]);}intsource=1;System.out.println("DFS from source: "+source);DFS(adj,source);}}
Python
defadd_edge(adj,s,t):# Add edge from vertex s to tadj[s].append(t)defdfs_rec(adj,visited,s):# Mark the current vertex as visitedvisited[s]=True# Print the current vertexprint(s,end=" ")# Recursively visit all adjacent vertices# that are not visited yetforiinadj[s]:ifnotvisited[i]:dfs_rec(adj,visited,i)defdfs(adj,s):visited=[False]*len(adj)# Call the recursive DFS functiondfs_rec(adj,visited,s)if__name__=="__main__":V=5# Create an adjacency list for the graphadj=[[]for_inrange(V)]# Define the edges of the graphedges=[[1,2],[1,0],[2,0],[2,3],[2,4]]# Populate the adjacency list with edgesforeinedges:add_edge(adj,e[0],e[1])source=1print("DFS from source:",source)dfs(adj,source)
C#
usingSystem;usingSystem.Collections.Generic;classGfG{staticvoidAddEdge(List<List<int>>adj,ints,intt){adj[s].Add(t);}// Recursive function for DFS traversalstaticvoidDFSRec(List<List<int>>adj,bool[]visited,ints){// Mark the current vertex as visitedvisited[s]=true;// Print the current vertexConsole.Write(s+" ");// Recursively visit all adjacent vertices// that are not visited yetforeach(intiinadj[s]){if(!visited[i]){DFSRec(adj,visited,i);}}}// Main DFS function that initializes the visited arraystaticvoidPerformDFS(List<List<int>>adj,ints){bool[]visited=newbool[adj.Count];// Call the recursive DFS functionDFSRec(adj,visited,s);}staticvoidMain(){intV=5;// Create an adjacency list for the graphList<List<int>>adj=newList<List<int>>(V);for(inti=0;i<V;i++){adj.Add(newList<int>());}// Define the edges of the graphint[,]edges={{1,2},{1,0},{2,0},{2,3},{2,4}};// Populate the adjacency list with edgesfor(inti=0;i<edges.GetLength(0);i++){AddEdge(adj,edges[i,0],edges[i,1]);}intsource=1;// Starting vertex for DFSConsole.WriteLine("DFS from source: "+source);PerformDFS(adj,source);}}
JavaScript
functionaddEdge(adj,s,t){// Add edge from vertex s to tadj[s].push(t);}functiondfsRec(adj,visited,s){// Mark the current vertex as visitedvisited[s]=true;// Print the current vertexprocess.stdout.write(s+" ");// Recursively visit all adjacent vertices that are not// visited yetfor(letiofadj[s]){if(!visited[i]){dfsRec(adj,visited,i);}}}functiondfs(adj,s){constvisited=newArray(adj.length).fill(false);// Call the recursive DFS functiondfsRec(adj,visited,s);}constV=5;// Number of vertices in the graph// Create an adjacency list for the graphconstadj=Array.from({length:V},()=>[]);// Define the edges of the graphconstedges=[[1,2],[1,0],[2,0],[2,3],[2,4]];// Populate the adjacency list with edgesfor(leteofedges){addEdge(adj,e[0],e[1]);}constsource=1;console.log("DFS from source: "+source);dfs(adj,source);
Output
DFS from source: 1
1 2 0 3 4
Time complexity: O(V + E), where V is the number of vertices and E is the number of edges in the graph. Auxiliary Space: O(V + E), since an extra visited array of size V is required, And stack size for recursive calls to DFSRec function.
DFS for Complete Traversal of Disconnected Directed Graphs
In a directed graph, edges have a specific direction means we can travel from one vertex to another only in the direction the edge points. A disconnectedgraph is one in which not all vertices are reachable from a single vertex.
The above implementation takes a source as an input and prints only those vertices that are reachable from the source and would not print all vertices in case of disconnected graph. Let us now talk about the algorithm that prints all vertices without any source and the graph maybe disconnected.
To handle such a graph in DFS, we must ensure that the DFS algorithm starts from every unvisited vertex and this results in covering all components of the graph
C++
#include<bits/stdc++.h>usingnamespacestd;voidaddEdge(vector<vector<int>>&adj,ints,intt){adj[s].push_back(t);}// Recursive function for DFS traversalvoidDFSRec(vector<vector<int>>&adj,vector<bool>&visited,ints){// Mark the current vertex as visitedvisited[s]=true;// Print the current vertexcout<<s<<" ";// Recursively visit all adjacent vertices that are not visited yetfor(inti:adj[s])if(visited[i]==false)DFSRec(adj,visited,i);}// Main DFS function to perform DFS for the entire graphvoidDFS(vector<vector<int>>&adj){vector<bool>visited(adj.size(),false);// Loop through all vertices to handle disconnected graphfor(inti=0;i<adj.size();i++){if(visited[i]==false){// If vertex i has not been visited,// perform DFS from itDFSRec(adj,visited,i);}}}intmain(){intV=6;// Create an adjacency list for the graphvector<vector<int>>adj(V);// Define the edges of the graphvector<vector<int>>edges={{1,2},{2,0},{0,3},{4,5}};// Populate the adjacency list with edgesfor(auto&e:edges)addEdge(adj,e[0],e[1]);cout<<"Complete DFS of the graph:"<<endl;DFS(adj);return0;}
C
#include<stdio.h>#include<stdlib.h>// Node structure for adjacency liststructNode{intdest;structNode*next;};// Structure to represent an adjacency liststructAdjList{structNode*head;};// Function to create a new adjacency list nodestructNode*createNode(intdest){structNode*newNode=(structNode*)malloc(sizeof(structNode));newNode->dest=dest;newNode->next=NULL;returnnewNode;}// Function to add an edge to the adjacency listvoidaddEdge(structAdjListadj[],ints,intt){// Add edge from s to tstructNode*newNode=createNode(t);newNode->next=adj[s].head;adj[s].head=newNode;}// Recursive function for DFS traversalvoidDFSRec(structAdjListadj[],intvisited[],ints){// Mark the current vertex as visitedvisited[s]=1;// Print the current vertexprintf("%d ",s);// Traverse all adjacent vertices that are not visited yetstructNode*current=adj[s].head;while(current!=NULL){intdest=current->dest;if(!visited[dest]){DFSRec(adj,visited,dest);}current=current->next;}}// Main DFS function to perform DFS for the entire graphvoidDFS(structAdjListadj[],intV){intvisited[6]={0};// Initialize visited array to false// Loop through all vertices to handle disconnected graphfor(inti=0;i<V;i++){if(visited[i]==0){// If vertex i has not been visited,// perform DFS from itDFSRec(adj,visited,i);}}}intmain(){intV=6;// Create an array of adjacency listsstructAdjListadj[V];// Initialize each adjacency list as emptyfor(inti=0;i<V;i++){adj[i].head=NULL;}constintE=4;// Define the edges of the graphintedges[][2]={{1,2},{2,0},{0,3},{4,5}};// Populate the adjacency list with edgesfor(inti=0;i<E;i++){addEdge(adj,edges[i][0],edges[i][1]);}printf("Complete DFS of the graph:\n");DFS(adj,V);return0;}
Java
importjava.util.ArrayList;importjava.util.List;classGfG{// Function to add an edge to the adjacency liststaticvoidaddEdge(List<List<Integer>>adj,ints,intt){adj.get(s).add(t);}// Recursive function for DFS traversalstaticvoidDFSRec(List<List<Integer>>adj,boolean[]visited,ints){visited[s]=true;System.out.print(s+" ");// Recursively visit all adjacent vertices that are// not visited yetfor(inti:adj.get(s)){if(!visited[i]){DFSRec(adj,visited,i);}}}// Main DFS function to perform DFS for the entire graphstaticvoidDFS(List<List<Integer>>adj,intV){boolean[]visited=newboolean[V];// Loop through all vertices to handle disconnected// graphfor(inti=0;i<V;i++){if(!visited[i]){DFSRec(adj,visited,i);}}}publicstaticvoidmain(String[]args){intV=6;// Create an adjacency list for the graphList<List<Integer>>adj=newArrayList<>();for(inti=0;i<V;i++){adj.add(newArrayList<>());}// Define the edges of the graphint[][]edges={{1,2},{2,0},{0,3},{4,5}};// Populate the adjacency list with edgesfor(int[]edge:edges){addEdge(adj,edge[0],edge[1]);}System.out.println("Complete DFS of the graph:");DFS(adj,V);}}
Python
classGraph:def__init__(self,vertices):# Adjacency listself.adj=[[]for_inrange(vertices)]defadd_edge(self,s,t):self.adj[s].append(t)defdfs_rec(self,visited,s):visited[s]=Trueprint(s,end=" ")# Recursively visit all adjacent vertices# that are not visited yetforiinself.adj[s]:ifnotvisited[i]:self.dfs_rec(visited,i)defdfs(self):visited=[False]*len(self.adj)# Loop through all vertices to handle disconnected# graphforiinrange(len(self.adj)):ifnotvisited[i]:# Perform DFS from unvisited vertexself.dfs_rec(visited,i)if__name__=="__main__":V=6# Number of verticesgraph=Graph(V)# Define the edges of the graphedges=[(1,2),(2,0),(0,3),(4,5)]# Populate the adjacency list with edgesforedgeinedges:graph.add_edge(edge[0],edge[1])print("Complete DFS of the graph:")graph.dfs()# Perform DFS
C#
usingSystem;usingSystem.Collections.Generic;classProgram{// Function to add an edge to the adjacency liststaticvoidAddEdge(List<List<int>>adj,(int,int)edge){adj[edge.Item1].Add(edge.Item2);}// Recursive function for DFS traversalstaticvoidDFSRec(List<List<int>>adj,bool[]visited,ints){// Mark the current vertex as visitedvisited[s]=true;// Print the current vertexConsole.Write(s+" ");// Recursively visit all adjacent vertices// that are not visited yetforeach(intiinadj[s]){if(!visited[i]){DFSRec(adj,visited,i);// Recursive call}}}// Main DFS function to perform DFS for the entire graphstaticvoidDFS(List<List<int>>adj){bool[]visited=newbool[adj.Count];// Loop through all vertices to handle// disconnected graphfor(inti=0;i<adj.Count;i++){if(!visited[i]){// If vertex i has not been visited,// perform DFS from itDFSRec(adj,visited,i);}}}staticvoidMain(){intV=6;// Create an adjacency list for the graphvaradj=newList<List<int>>(newList<int>[V]);for(inti=0;i<V;i++){adj[i]=newList<int>();// Initialize each list}// Define the edges of the graph using tuplesvaredges=newList<(int,int)>{(1,2),(2,0),(0,3),(4,5)};// Populate the adjacency list with edgesforeach(varedgeinedges){AddEdge(adj,edge);}Console.WriteLine("Complete DFS of the graph:");DFS(adj);}}
JavaScript
functionaddEdge(adj,s,t){adj[s].push(t);}// Recursive function for DFS traversalfunctionDFSRec(adj,visited,s){visited[s]=true;console.log(s+" ");// Recursively visit all adjacent vertices that are not// visited yetadj[s].forEach(i=>{if(!visited[i]){DFSRec(adj,visited,i);}});}// Main DFS function to perform DFS for the entire graphfunctionDFS(adj,V){letvisited=newArray(V).fill(false);// Loop through all vertices to handle disconnected// graphfor(leti=0;i<V;i++){if(!visited[i]){DFSRec(adj,visited,i);}}}// Driver codeletV=6;// Create an adjacency list for the graphletadj=newArray(V);for(leti=0;i<V;i++){adj[i]=[];}// Define the edges of the graphletedges=[[1,2],[2,0],[0,3],[4,5]];// Populate the adjacency list with edgesedges.forEach(edge=>{addEdge(adj,edge[0],edge[1]);});console.log("Complete DFS of the graph:");DFS(adj,V);
Output
Complete DFS of the graph:
0 2 1 3 4 5
Time Complexity: O(V + E). Note that the time complexity is same here because we visit every vertex at most once and every edge is traversed at most once (in directed) and twice in undirected. Auxiliary Space: O(V + E), since an extra visited array of size V is required, And stack size for recursive calls to DFSRec function.