Home > Back-end >  Breadth First Traversal in Haskell
Breadth First Traversal in Haskell

Time:11-05

I need to find all the paths in a tree-like structure.

enter image description here

I recently defined Deep First traversal (or iterate) as follows:

dfIterate:: (a -> [a]) -> a -> [[a]]
dfIterate f a = map (a:) ([] : concatMap (dfIterate f) (f a))

It takes a seed a and a function a -> [a] (from each "a", you can get to multiple a's). The result is a list of paths starting from the seed. It works well:

ghci> let f a = if a == 1 then [2, 3] else if a == 2 then [4] else []
ghci> dfIterate f 1
[[1],[1,2],[1,2,4],[1,3]]

My function dfIterate iterates correctly and shows me all the paths. The function f simulates the tree above.

But how to make a "Breadth First Traversal"? The result in this case should be: [[1],[1,2],[1,3],[1,2,4]]. My first attempt:

bfIterate :: (a -> [a]) -> [a] -> [[a]]
bfIterate _ [] = [[]]
bfIterate f (a:as) = map (a:) (bfIterate f (as    (f a)))

I tried to use the second argument as a queue. I know I'm quite far from the result... Thanks

EDIT: This link gives interesting lines of approach: Breadth-First Search using State monad in Haskell. However, my question is about finding all paths (i.e. [[a]]), while that question is for finding single solutions (i.e. [a])

CodePudding user response:

Correctness first, efficiency later.

bfPaths :: (a -> [a]) -> a -> [[a]]
bfPaths step seed  =  go [ (seed, [seed]) ]
 where
 go []  =  []
 go ((s, path) : q) = path :
   go (q    [ (x, path    [x]) | x <- step s ])

indeed maintaining a queue and adding the nodes to it, level by level.

Trying it:

> bfPaths f 1
[[1],[1,2],[1,3],[1,2,4]]

Now you can look for ways to make it more efficient.

  • Related