Saturday, February 14, 2015

Depth First Search (DFS) - Graphs


In DFS, we start from a vertex and try to move forward and explore vertices, till we find that all the next edges lead to vertices which have already been visited. Then we backtrack along the same path, and try to explore other possibilities.

DFS divides the edges of a graph into 2 categories:
1. Tree edges: Edges through which we reached(discovered) a vertex for the first time, i.e., edges leading to an unexplored vertex.
2. Back edges: Edges which lead back to a vertex already visited.
In the following figure [b], tree edges are shown in dark bold, and back edges are shown in dotted lines.

Depth First Search


We also define 2 time-stamps associated with each vertex of the graph, namely:
Arrival time: The time at which the vertex was explored for the first time, and
Departure time: The time at which we have explored all the neighbors of the vertex and we are ready to backtrack.

In the following diagram[b], arrival/departure time slots are shown for each vertex. These time slots are not really used in this example, as we are just exploring the vertices using DFS (Depth-First Search), but will be really useful when we will be studying the applications of DFS including topological sort of vertices based on their departure times.
Algorithm:

DFS(G, s, V, E, arr[], dep[]):
G = the graph
V = set of vertices
E = set of edges
s = starting vertex

        time = 0; 
        visited[s] = true;
        arr[s] = time++;
 
        for all adjacent vertices w of s :
                if( !visited[w]) {
                        DFS(w)
                }
        dep[s] = time++;

Implementation: 

/*
* DFS.cpp
*
* Created on: Feb 14, 2015
* Author: CodingTonic
*/

#include <iostream>
#include <list>
using namespace std;

#define INF 100

// structure defining Node or vertex of a Graph
struct Node
{
    int vert;
    int weight;
    Node(int _v, int _w): vert(_v), weight(_w)
    {
        ;
    }
};

class Graph
{
    int numVert;
    list<Node> *adjList;
public:
    // Constructor for Graph class
    Graph(int nV): numVert(nV)
    {
        adjList = new list<Node>[nV];
    }
    // Destructor
    ~Graph()
    {
        delete []adjList;
    }

    void AddEdge(int u, int v, int w)
    {
        adjList[u].push_back(Node(v, w));
    }

    // Function for Depth-first traversal of Graph
    void DFS(int s, bool bVisited[], int arr[], int dep[])
    {
        bVisited[s] = true;
        static int _time = 0;
        arr[s] = _time++;
        list<Node>::iterator it;
        for(it = adjList[s].begin(); it != adjList[s].end(); it++)
        {
            if(!bVisited[it->vert])
            {
                DFS(it->vert, bVisited, arr, dep);
            }
        }
        dep[s] = _time++;
    }
};

// main function
int main(int argc, char* argv[])
{
    Graph G(5);
    G.AddEdge(0, 1, 1);
    G.AddEdge(0, 3, 2);
    G.AddEdge(1, 2, 5);
    G.AddEdge(1, 3, 1);
    G.AddEdge(2, 4, 4);
    G.AddEdge(3, 2, 3);
    G.AddEdge(3, 4, 7);

    bool visited[5] = {false, false, false, false, false};
    int arr[5] = {-1, -1, -1, -1, -1}; // arrival time-first time a node is visited
    int dep[5] = {-1, -1, -1, -1, -1}; // departure time - the node and all its neighbors are visited
    G.DFS(0, visited, arr, dep);
    for(int i=0; i<5; i++)
    {
        cout << i << ": visited = " << visited[i] << ", arr = " << arr[i] << ", dep = " << dep[i] << endl;
    }

    return (0);
}

/*         1         5
 *  [0]------->[1]------->[2]
 *     \        |        ^ |
 *      \       |       /  |
 *       \      |      /   |
 *      2 \    1|   3 /    |4
 *         \    |    /     |
 *          \   |   /      |
 *           V  v  /       v
 *            [3]-------->[4]
 *                  7
 * */

 

Output:   
0: visited = 1, arr = 0, dep = 9
1: visited = 1, arr = 1, dep = 8
2: visited = 1, arr = 2, dep = 5
3: visited = 1, arr = 6, dep = 7
4: visited = 1, arr = 3, dep = 4

No comments :

Post a Comment