As svenningsson suggests, the priority search queue works well for both Kruskal and Prim (at least the author proclaims this in his paper .) The problem with Kruskal is that it requires you to have O (log n ) join-search algorithm . The structural structure of the association with a purely functional interface is described here, but it uses a volatile state within the country, and a purely functional implementation may not be possible, and in fact there are several problems when an effective purely functional solution is unknown, as discussed in this relevant SO issue .
An unclean alternative is to implement the union-find algorithm in ST monad. A search in Hackage discovers that the equivalence package meets our needs. The following is an implementation of Kruskal using Data.Equivalence.Monad from the equivalence package:
import Data.Equivalence.Monad import Data.Graph as G import Data.List(sortBy) import Data.Map as M import Control.Monad(filterM) import Data.Ord(comparing) run = runEquivM (const ()) (const $ const ()) kruskal weight graph = run $ filterM go (sortBy (comparing weight) theEdges) where theEdges = G.edges graph go (u,v) = do eq <- equivalent uv if eq then return False else equate uv >> return True
It can be used as follows:
fromL xs = fromJust . flip M.lookup (M.fromList xs) testWeights = fromL [((1,2),1),((2,3),4),((3,4),5),((1,4),30),((1,3),4)] testGraph = G.buildG (1,4) [(1,2),(2,3),(3,4),(1,4),(1,3)] test = kruskal testWeights testGraph
and current testing gives:
[(1,2),(1,3),(3,4)]
It should be noted that the runtime depends on the weight performed in O (1), however fromL creates a weight function executed in O (log (n)), this can be improved to O (1) using arrays or just tracking the weight in the list input, but this is not part of the algorithm.