7

I've been banging my head over the wall for a few hours as I can't figure out how to write DFS in Haskell..

My graph is implemented as an adjacency list where the keys (or node name of the graph) are list indices:

0 -> 1
1 -> 0, 2
2 -> 1

As a Haskell list: [[1],[0,2],[1]]

Here's my code so far for DFS:

dfs graph visited node = helper graph visited (graph !! node) node
    where helper _ _ visited [] _ = visited
          helper graph visited (x:xs) currNode
            | elem x visited = helper graph visited xs currNode
            | otherwise = dfs graph (currNode:visited) x

I understand that the problem is that it doesn't backtrack and try another adjacent node once it reaches one end of the graph. I've been trying to modify the otherwise section of the guard in an attempt to fix it but can't seem to come up with something that works. What can I do to fix this?

Dominique Fortin
  • 2,212
  • 15
  • 20
Coding District
  • 11,901
  • 4
  • 26
  • 30
  • Does that even compile ? Also the complexity of `!!` is O(n) in worst case, so the complexity of your dfs will be much larger. – Satvik Oct 05 '12 at 03:49
  • If this isn't homework, you may want to use the Functional Graph Library (fgl). It looks daunting with tons of modules but it's actually easy to use. – Dietrich Epp Oct 05 '12 at 03:54
  • This is too little for an answer but take a look at this paper: "Structuring Depth-First Search Algorithm in Haskell" www.researchgate.net/publication/2252048_Structuring_Depth-First_Search_Algorithms_in_Haskell/file/50463523c7a64b12d4.pdf – it's not the easiest to grasp but… Well, should perform well. I'll do testing a bit later. – kgadek Jul 28 '14 at 11:09

2 Answers2

3

What you are trying to do is still not very clear to me. I have written something similar to yours although it has the same problem that !! is not O(1), but it is still dfs.

mydfs graph visited [] = reverse visited
mydfs graph visited (x:xs) | elem x visited = mydfs graph visited xs
                           | otherwise = mydfs graph (x:visited) ((graph !! x) ++ xs)

The idea for dfs to backtrack is to keep a list of tobevisited and just take out the first entry from it and visit it and whenever you find an entry that is not visited push its adjacent vertices on top of the tobevisited list.

You can use arrays or vectors for adjacency list to avoid O(n) lookup, but it is better to use graph libraries for what you are trying to do.

Satvik
  • 11,238
  • 1
  • 38
  • 46
3

Shortest I could come up with

dfs current visited =
    foldl (\visited next -> if elem next visited then visited else dfs next visited)
           (visited ++ [current]) (graph !! current)

Compare with python:

def dfs(v, visited):
    visited.append(v)
    for u in graph[v]:
        if u not in visited:
            visited = dfs(u, visited)
    return visited
theluckyemil
  • 663
  • 1
  • 7
  • 16