How to implement depth first search for graph with a non-recursive approach

前端 未结 13 1752
情话喂你
情话喂你 2020-11-28 22:00

I have spent lots of time on this issue. However, I can only find solutions with non-recursive methods for a tree: Non recursive for tree, or a recursive method for the grap

相关标签:
13条回答
  • 2020-11-28 22:11

    okay. if you are still looking for a java code

    dfs(Vertex start){
        Stack<Vertex> stack = new Stack<>(); // initialize a stack
        List<Vertex> visited = new ArrayList<>();//maintains order of visited nodes
        stack.push(start); // push the start
        while(!stack.isEmpty()){ //check if stack is empty
            Vertex popped = stack.pop(); // pop the top of the stack
            if(!visited.contains(popped)){ //backtrack if the vertex is already visited
                visited.add(popped); //mark it as visited as it is not yet visited
                for(Vertex adjacent: popped.getAdjacents()){ //get the adjacents of the vertex as add them to the stack
                        stack.add(adjacent);
                }
            }
        }
    
        for(Vertex v1 : visited){
            System.out.println(v1.getId());
        }
    }
    
    0 讨论(0)
  • 2020-11-28 22:11

    Acutally, stack is not well able to deal with discover time and finish time, if we want to implement DFS with stack, and want to deal with discover time and finish time, we would need to resort to another recorder stack, my implementation is shown below, have test correct, below is for case-1, case-2 and case-3 graph.

    from collections import defaultdict
    
    class Graph(object):
    
        adj_list = defaultdict(list)
    
        def __init__(self, V):
            self.V = V
    
        def add_edge(self,u,v):
            self.adj_list[u].append(v)
    
        def DFS(self):
            visited = []
            instack = []
            disc = []
            fini = []
            for t in range(self.V):
                visited.append(0)
                disc.append(0)
                fini.append(0)
                instack.append(0)
    
            time = 0
            for u_ in range(self.V):
                if (visited[u_] != 1):
                    stack = []
                    stack_recorder = []
                    stack.append(u_)
                    while stack:
                        u = stack.pop()
                        visited[u] = 1
                        time+=1
                        disc[u] = time
                        print(u)
                        stack_recorder.append(u)
                        flag = 0
                        for v in self.adj_list[u]:
                            if (visited[v] != 1):
                                flag = 1
                                if instack[v]==0:
                                    stack.append(v)
                                instack[v]= 1
    
    
    
                        if flag == 0:
                            time+=1
                            temp = stack_recorder.pop()
                            fini[temp] = time
                    while stack_recorder:
                        temp = stack_recorder.pop()
                        time+=1
                        fini[temp] = time
            print(disc)
            print(fini)
    
    if __name__ == '__main__':
    
        V = 6
        G = Graph(V)
    
    #==============================================================================
    # #for case 1
    #     G.add_edge(0,1)
    #     G.add_edge(0,2)
    #     G.add_edge(1,3)
    #     G.add_edge(2,1)
    #     G.add_edge(3,2) 
    #==============================================================================
    
    #==============================================================================
    # #for case 2
    #     G.add_edge(0,1)
    #     G.add_edge(0,2)
    #     G.add_edge(1,3)
    #     G.add_edge(3,2)  
    #==============================================================================
    
    #for case 3
        G.add_edge(0,3)    
        G.add_edge(0,1)
    
        G.add_edge(1,4)
        G.add_edge(2,4)
        G.add_edge(2,5)
        G.add_edge(3,1)
        G.add_edge(4,3)
        G.add_edge(5,5)    
    
    
        G.DFS()   
    
    0 讨论(0)
  • 2020-11-28 22:13

    Recursion is a way to use the call stack to store the state of the graph traversal. You can use the stack explicitly, say by having a local variable of type std::stack, then you won't need the recursion to implement the DFS, but just a loop.

    0 讨论(0)
  • 2020-11-28 22:14

    The DFS logic should be:

    1) if the current node is not visited, visit the node and mark it as visited
    2) for all its neighbors that haven't been visited, push them to the stack

    For example, let's define a GraphNode class in Java:

    class GraphNode {
        int index;
        ArrayList<GraphNode> neighbors;
    }
    

    and here is the DFS without recursion:

    void dfs(GraphNode node) {
        // sanity check
        if (node == null) {
            return;
        }
    
        // use a hash set to mark visited nodes
        Set<GraphNode> set = new HashSet<GraphNode>();
    
        // use a stack to help depth-first traversal
        Stack<GraphNode> stack = new Stack<GraphNode>();
        stack.push(node);
    
        while (!stack.isEmpty()) {
            GraphNode curr = stack.pop();
    
            // current node has not been visited yet
            if (!set.contains(curr)) {
                // visit the node
                // ...
    
                // mark it as visited
                set.add(curr);
            }
    
            for (int i = 0; i < curr.neighbors.size(); i++) {
                GraphNode neighbor = curr.neighbors.get(i);
    
                // this neighbor has not been visited yet
                if (!set.contains(neighbor)) {
                    stack.push(neighbor);
                }
            }
        }
    }
    

    We can use the same logic to do DFS recursively, clone graph etc.

    0 讨论(0)
  • 2020-11-28 22:14

    Python code. The time complexity is O(V+E) where V and E are the number of vertices and edges respectively. The space complexity is O(V) due to the worst-case where there is a path that contains every vertex without any backtracking (i.e. the search path is a linear chain).

    The stack stores tuples of the form (vertex, vertex_edge_index) so that the DFS can be resumed from a particular vertex at the edge immediately following the last edge that was processed from that vertex (just like the function call stack of a recursive DFS).

    The example code uses a complete digraph where every vertex is connected to every other vertex. Hence it is not necessary to store an explicit edge list for each node, as the graph is an edge list (the graph G contains every vertex).

    numv = 1000
    print('vertices =', numv)
    G = [Vertex(i) for i in range(numv)]
    
    def dfs(source):
      s = []
      visited = set()
      s.append((source,None))
      time = 1
      space = 0
      while s:
        time += 1
        current, index = s.pop()
        if index is None:
          visited.add(current)
          index = 0
        # vertex has all edges possible: G is a complete graph
        while index < len(G) and G[index] in visited:
          index += 1
        if index < len(G):
          s.append((current,index+1))
          s.append((G[index], None))
        space = max(space, len(s))
      print('time =', time, '\nspace =', space)
    
    dfs(G[0])
    

    Output:

    time = 2000 
    space = 1000
    

    Note that time here is measuring V operations and not E. The value is numv*2 because every vertex is considered twice, once on discovery and once on finishing.

    0 讨论(0)
  • 2020-11-28 22:16

    A recursive algorithm works very well for DFS as we try to plunge as deeply as we can, ie. as soon as we find an un-explored vertex, we're going to explore its FIRST un-explored neighbor right away. You need to BREAK out of the for loop as soon as you find the first un-explored neighbor.

    for each neighbor w of v
       if w is not explored
           mark w as explored
           push w onto the stack
           BREAK out of the for loop
    
    0 讨论(0)
提交回复
热议问题