Depth First Search - kgleong/software-engineering GitHub Wiki

Implementation

Use DFS to return a path (if one exists) from one vertex to another.

Recursive implementation

List<Vertex> DFS(Vertex vertex,
                Vertex vertexToFind,
                List<Vertex> path,
                Set<Vertex> visitedVertexList) {
    List<Vertex> pathToEnd = null;

    if(vertex == vertexToFind) {
        pathToEnd = path;
        pathToEnd.add(vertexToFind);
    }
    else if(vertex != null) {
        for(Vertex neighbor : vertex.adjacencyList) {
            if(!vistedVertexList.contains(neighbor)) {
                vistedVertexList.add(neighbor);

                List<Vertex> pathIncludingNeighbor = new ArrayList<>(path);
                pathIncludingNeighbor.add(neighbor);

                pathToEnd = DFS(neighbor,
                                vertexToFind,
                                pathIncludingNeighbor,
                                visitedVertexList)

                if(pathToEnd != null) {
                    return;
                }
            }
        }
    }
    return pathToEnd;
}

public class Vertex {
    public List<Vertex> adjacencyList;
}

Iterative implementation

DFS implemented using a stack.

List<Vertex> DFS(Vertex start, Vertex end) {
    List<Vertex> pathToEnd = null;

    Set<Vertex> visitedVertexList = new HashSet<>();
    Stack<StackEntry> verticesToProcess = new Stack<>();

    verticesToProcess.push(new StackEntry(vertex, new ArraryList<>());

    while(!verticesToProcess.empty()) {
        StackEntry entry = verticesToProcess.pop();

        for(Vertex neighbor : entry.vertex.adjacencyList) {
            // Make a copy of the path so far since possible paths
            // will be parallel branches.
            List<Vertex> currentPath = new ArrayList<>(entry.path);
            currentPath.add(neighbor);

            if(neighbor == end) {
                pathToEnd = currentPath;
                break;
            }
            if(!visitedVertexList.contains(neighbor)) {
                // Push onto stack a new stack entry.
                // Since a stack is LIFO, this provides the
                // depth-first traversal of the graph.
                verticesToProcess.push(new StackEntry(vertex, currentPath));
            }
        }
        if(pathToEnd != null) {
            // A path has been found.
            break;
        }
    }
    return pathToEnd;
}

public class StackEntry {
    public Vertex vertex;
    public List<Vertex> path;

    public StackEntry(Vertex vertex, List<Vertex> path) {
        this.vertex = vertex;
        this.path = path;
    }
}

Runtime and Memory Analysis

The runtime of DFS is O(V + E).

  • V: number of vertices in the graph.
  • E: number of edges in the graph.

The space required for DFS is O(V).

  • May need to store a set of already visited vertices.
  • If a stack is used, in the worst case all vertices would need to be pushed onto the stack while searching.

References

DFS - Wikipedia

⚠️ **GitHub.com Fallback** ⚠️