Running DFS on a connected graph generates a DFS spanning tree (or spanning forest if the graph is disconnected). With the help of one more vertex state: EXPLORED (visited but not yet completed) on top of VISITED (visited and completed), we can use this DFS spanning tree (or forest) to classify graph edges into three types:
- Tree edge: The edge traversed by DFS, i.e. an edge from a vertex currently with state:
EXPLORED to a vertex with state: UNVISITED. - Back edge: Edge that is part of a cycle, i.e. an edge from a vertex currently with state:
EXPLORED to a vertex with state: EXPLORED too. This is an important application of this algorithm. Note that we usually do not count bi-directional edges as having a ‘cycle’ (We need to remember the parent of each node to distinguish this). - Forward/Cross edges from vertex with state: EXPLORED to vertex with state: VISITED.
Consider the following graph:
In the following picture, and as shown from left to right, we call dfs(0), then dfs(5), and finally dfs(6) on the above graph. We can see that \(1 \rightarrow 2 \rightarrow 3 \rightarrow 1\) is a (true) cycle and we classify edge (\(3 \rightarrow 1\)) as a back edge, whereas \(0 \rightarrow 1 \rightarrow 0\) is not a cycle but it is just a bi-directional edge (\(0-1\)).
Note that a spanning tree of a connected graph G is a tree that spans (covers) all vertices of G but only using a subset of the edges of G. A disconnected graph G has several connected components. Each component has its own spanning subtree(s). All spanning subtrees of G, one from each component, form what we call a spanning forest.
An adaptation from CP3 of Steven and Felix Halim.
Difficulty level
Video recording
This exercise is mostly suitable for students
#include<stdio.h>
#include<stdlib.h>
typedef struct {
int V;
int E;
int **Adj; // since we need 2 dimensional matrix
} Graph;
Graph* adjacencyMatrix() {
int i, u, v;
Graph* G=(Graph*) malloc(sizeof(Graph));
printf("Enter the number of Vertices: ");
scanf("%d", &G->V);
printf("Enter the number of Edges: ");
scanf("%d", &G->E);
G->Adj = (int **)malloc(G->V * sizeof(int*));
for (u = 0; u < G->V; u++)
G->Adj[u] = (int *)malloc(G->V * sizeof(int));
for (u = 0; u<G->V; u++)
for (v = 0; v<G->V; v++)
G->Adj[u][v] = 0;
for (i = 0; i < G->E; i++) {
printf("Enter the edge: ");
scanf("%d %d", &u,&v);
// for undirected graph, set both
G->Adj[u][v] = 1;
G->Adj[v][u] = 1;
}
return G;
}
enum color{EXPLORED,UNVISITED, VISITED};
void graphCheck(Graph* G, int u, int Visited[], int Parent[]) { // DFS for checking graph edge properties
int j;
Visited[u]=EXPLORED; // color u as EXPLORED instead of VISITED
for (j = 0; j < G->V; j++)
{
if(G->Adj[u][j]==1)
{
if(Visited[j]==UNVISITED) // Tree edge, EXPLORED -> UNVISITED
{
Parent[j]=u;
graphCheck(G, j, Visited, Parent);
}
else
if(Visited[j]==EXPLORED) // 2 options, EXPLORED -> EXPLORED
{
if(j==Parent[u]) // to differentiate these two cases
printf(" Two ways (%d, %d)-(%d, %d)\n", u, j, j, u);
else // the most frequent application: check if the graph is cyclic
printf(" Back Edge (%d, %d) (Cycle)\n", u, j);
}
else
if(Visited[j]==VISITED) // EXPLORED -> VISITED
printf(" Forward/Cross Edge (%d, %d)\n", u, j);
}
}
Visited[u]=VISITED; // after recursion, color u as VISITED (DONE)
}
void DFS(Graph *G) {
int i, numComp;
int *Visited, *Parent;
Visited = (int *)malloc(G->V * sizeof(int));
Parent = (int *)malloc(G->V * sizeof(int));
numComp=0;
for (i = 0; i < G->V; i++)
{
Visited[i] = UNVISITED;
Parent[i]=0;
}
// this loop is required if the graph has more than one component
for (i = 0; i < G ->V; i++)
if (Visited[i]==UNVISITED)
{
printf("Component %d:\n", ++numComp);
graphCheck(G, i, Visited, Parent);
}
}
void test() {
int u, v;
Graph *G = adjacencyMatrix();
DFS(G);
}
int main()
{
test();
return 0;
}
For the sample graph, the output is like this:
Component 1:
Two ways (1, 0) - (0, 1)
Two ways (2, 1) - (1, 2)
Back Edge (3, 1) (Cycle)
Two ways (3, 2) - (2, 3)
Two ways (4, 3) - (3, 4)
Forward/Cross Edge (1, 3)
Component 2:
Component 3:
Two ways (7, 6) - (6, 7)
Two ways (8, 6) - (6, 8)
Back to the list of exercises
Looking for a more challenging exercise, try this one !!
Sorting using the counting sort algorithm