10

Can you please let me know what is incorrect in below DFS code. It's giving correct result AFAIK, but I don't know when it will fail.

graph1 = {
    'A' : ['B','S'],
    'B' : ['A'],
    'C' : ['D','E','F','S'],
    'D' : ['C'],
    'E' : ['C','H'],
    'F' : ['C','G'],
    'G' : ['F','S'],
    'H' : ['E','G'],
    'S' : ['A','C','G']
}

visited = []

def dfs(graph,node):
    global visited
    if node not in visited:
        visited.append(node)
        for n in graph[node]:
            dfs(graph,n)

    dfs(graph1,'A')
    print(visited)

Output:

['A', 'B', 'S', 'C', 'D', 'E', 'H', 'G', 'F']
Juan Leni
  • 6,982
  • 5
  • 55
  • 87
Vicky
  • 161
  • 1
  • 1
  • 6
  • 2
    First of all: don't use `global`s avoid them as much as possible!! – Willem Van Onsem Apr 15 '17 at 19:24
  • 2
    DFS is a *search* algorithm, but there is *no target* defined you are looking for... – Willem Van Onsem Apr 15 '17 at 19:28
  • Thanks for the response.. visited = [] def dfs(graph,node,visited): if node not in visited: visited.append(node) for n in graph[node]: dfs(graph,n,visited) dfs(graph1,'A',visited) print(visited) – Vicky Apr 15 '17 at 19:29
  • I'm also not convinced that the output you show is generated by the data you show - I don't see where S, H and G come from? (But I could possibly be wrong here) – DavidW Apr 15 '17 at 19:32
  • Hi Willem, if you checkout the link http://eddmann.com/posts/depth-first-search-and-breadth-first-search-in-python/ there a sample code for the DFS is given but If I change the graph as given in youtube tutorial "https://youtu.be/iaBEKo5sM7w" I am not getting the result as mentioned. So I thought of writing my own version based on the tutorial. – Vicky Apr 15 '17 at 19:34
  • Expected output doesn't match your test case. The algorithm looks OK to me. – k5f Apr 15 '17 at 19:37
  • Hi David, thanks for noticing, I had pasted wrong input which I fixed now – Vicky Apr 15 '17 at 19:39

9 Answers9

19

I think you have an indentation problem there. Assuming your code looks like this:

graph1 = {
    'A' : ['B','S'],
    'B' : ['A'],
    'C' : ['D','E','F','S'],
    'D' : ['C'],
    'E' : ['C','H'],
    'F' : ['C','G'],
    'G' : ['F','S'],
    'H' : ['E','G'],
    'S' : ['A','C','G']
}

visited = []

def dfs(graph,node):
    global visited
    if node not in visited:
        visited.append(node)
        for n in graph[node]:
            dfs(graph,n)

dfs(graph1,'A')
print(visited)

I would say a couple of things:

  • Avoid globals if you can
  • Instead of a list for visited, use a set

plus:

  • This will not work for forests but I assume you already know that
  • It will fail if you reference a node that does not exist.

Updated code:

graph1 = {
    'A' : ['B','S'],
    'B' : ['A'],
    'C' : ['D','E','F','S'],
    'D' : ['C'],
    'E' : ['C','H'],
    'F' : ['C','G'],
    'G' : ['F','S'],
    'H' : ['E','G'],
    'S' : ['A','C','G']
}

def dfs(graph, node, visited):
    if node not in visited:
        visited.append(node)
        for n in graph[node]:
            dfs(graph,n, visited)
    return visited

visited = dfs(graph1,'A', [])
print(visited)
Juan Leni
  • 6,982
  • 5
  • 55
  • 87
  • 3
    Should the updated code contain the variable `visited` as `dict` or `list`? – Sudarshan Jul 23 '17 at 05:26
  • @Sudarshan since it says ```visited.append(node)``` the variable visited is a list. – oamandawi Mar 02 '20 at 01:27
  • @Juan Leni or anyone listening: In the for loop of your code, how is variable n not stuck in values between 'B' and 'A' and how come it jumps to 'S' in the third iteration? – MM Khan Apr 25 '20 at 18:58
  • `visited` should be a set to reduce runtime by o(n) – Gulzar Aug 04 '22 at 07:34
  • making visited a bit vector reduces checks to O(1), but one could instead store for every vertex the adjacent vertices in sets and remove visited vertices directly from them. – user2961818 Jun 30 '23 at 09:22
13

Without recursion:

def dfs(graph, node):
    visited = set((node,))
    output = [node]
    stack = [node]
    while stack:
        node = stack[-1]
        if node not in visited:
            output.append(node)
            visited.add(node)
        remove_from_stack = True
        for next_node in graph[node]:
            if next_node not in visited:
                stack.append(next_node)
                remove_from_stack = False
                break
        if remove_from_stack:
            stack.pop()
    return output

print (dfs(graph1, 'A'))

Output:

['A', 'B', 'S', 'C', 'D', 'E', 'H', 'G', 'F']
Gulzar
  • 23,452
  • 27
  • 113
  • 201
gaetano
  • 865
  • 1
  • 15
  • 29
5

Here's an iterative (non-recursive) implementation of a DFS:

def dfs_iterative(graph, start_vertex):
    visited = set()
    traversal = []
    stack = [start_vertex]
    while len(stack) > 0:
        vertex = stack.pop()
        if vertex not in visited:
            visited.add(vertex)
            traversal.append(vertex)
            stack.extend(reversed(graph[vertex]))   # add vertex in the same order as visited
    return traversal

test_graph = {
    'A' : ['B','S'],
    'B' : ['A'],
    'C' : ['D','E','F','S'],
    'D' : ['C'],
    'E' : ['C','H'],
    'F' : ['C','G'],
    'G' : ['F','S'],
    'H' : ['E','G'],
    'S' : ['A','C','G']
}

print(dfs_iterative(test_graph, 'A'))

Output:

['A', 'B', 'S', 'C', 'D', 'E', 'H', 'G', 'F']

Gulzar
  • 23,452
  • 27
  • 113
  • 201
Saurabh
  • 5,176
  • 4
  • 32
  • 46
1
from collections import defaultdict

class Graph:
    def __init__(self):
        self.graph = defaultdict(list)

    def addEdge(self,u,v):
        self.graph[u].append(v)

    def DFS(self,v,vertex):
        visited = [False]*vertex
        print(self. graph)
        # print(len(self.graph),"+++")
        self.DFSUtil(v,visited)

    def DFSUtil(self,v,visited):
        visited[v]=True
        print(v)

        for i in self.graph[v]:
            if visited[i] == False:
                # print(visited)
                self.DFSUtil(i,visited)
g= Graph()

vertex=7

g.addEdge(0,1)
g.addEdge(0,2)
g.addEdge(0,6)
g.addEdge(0,5)
g.addEdge(5,3)
g.addEdge(5,4)
g.addEdge(4,3)
g.addEdge(6,4)

g.DFS(0,vertex) 

This is the modification for the above code because that doesn't work with in all cases.
We have to specify the number of vectors and then give edges manually.

Yuca
  • 6,010
  • 3
  • 22
  • 42
Aslesha Ch
  • 26
  • 2
0

DFS implementation in Python

from collections import defaultdict

class Graph:
    def __init__(self):
        self.graph = defaultdict(list)

    def addEdge(self, u, v):
        self.graph[u].append(v)

    def DFSUtil(self, v, visited):
        visited[v]=True
        print(v)

        for i in self.graph[v]:
            if visited[i] == False:
                self.DFSUtil(i, visited)

    def DFS(self):
        V = len(self.graph)

        visited = [False]*(V)

        for i in range(V):
            if visited[i] == False:
                self.DFSUtil(i, visited)

# Driver code
# Create a graph given in the above diagram
g = Graph()
g.addEdge(0, 1)
g.addEdge(0, 2)
g.addEdge(1, 2)
g.addEdge(2, 0)
g.addEdge(2, 3)
g.addEdge(3, 3)

print("Following is Depth First Traversal")
g.DFS()

Source :: this

Community
  • 1
  • 1
Akash Kandpal
  • 3,126
  • 28
  • 25
0
 graph = {'A': ['B', 'C'],
         'B': ['A', 'D', 'E'],
         'C': ['A', 'F'],
         'D': ['B'],
         'E': ['B', 'F'],
         'F': ['C', 'E']}

   def dfs(s,d):
    def dfs_helper(s,d):
        if s == d:
            return True
        if  s in visited :
            return False
        visited.add(s)
        for c in graph[s]:
            dfs_helper(c,d)
        return False
    visited = set()
    return dfs_helper(s,d) 
dfs('A','E') ---- True
dfs('A','M') ---- False
Sneha Mule
  • 641
  • 8
  • 6
0

Here is a more versatile algorithm, the one asked in the question works only for undirected graphs. But this hopefully works for both them. Check it out

graph1= {
'A' : ['B','S'],
'B' : [],
'C' : ['E','S'],
'D' : ['C'],
'E' : ['H'],
'F' : ['C'],
'G' : ['F','S'],
'H' : ['G'],
'S' : []
}
visited = []

def dfs_visit(graph, s):
    global visited
    for v in graph[s]:
        if v not in visited:
            visited.append(v)
            dfs_visit(graph, v)


def dfs(graph):
    global visited
    for v in [*graph]:
        if v not in visited:
            visited.append(v)
            dfs_visit(graph,v)

dfs(graph1)
print(visited)
Ramesses2
  • 1
  • 3
0
    def DFS(graph,pointer,visit):
          visit.add(pointer)
          print(pointer,end=' ')

    for travel in graph[pointer]-visit:
        if travel not in visit:
            DFS(graph,travel,visit)


graph={'0':set(['1','2','3']),'1':set(['0','2']),'2':set(['0','1','4']),'3':set(['0']),'4':set(['2'])}
visit=set()
print("DFS for graph: ",graph)
DFS(graph,'0',visit)

Output

DFS for graph:  {'0': {'1', '3', '2'}, '1': {'0', '2'}, '2': {'1', '0', '4'}, '3': {'0'}, '4': {'2'}}
0 1 2 4 3 

0

A recursive implementation:

def dfs(G, u, visited=[]):
    """Recursion version for depth-first search (DFS).
    Args:
        G: a graph
        u: start
        visited: a list containing all visited nodes in G
    Return:
        visited
    """
    visited.append(u)
    for v in G[u]:
        if v not in visited:
            dfs(G, v, visited)
    return visited

An iterative implementation using a stack:

def dfs_iterative(G, u, visited=[]):
    stack = [u, ] #initialize
    while stack:
        u = stack.pop()
        if u not in visited:
            visited.append(u)
            stack.extend(reversed(G[u])) #reversed() is used as the same traversal as recursive DFS
    return visited
user
  • 1,220
  • 1
  • 12
  • 31