It is also possible to avoid visiting the same edge twice by removing it from the list of available edges; assuming order does not matter in among edges, you can remove an edge as follows:
let edges_remove_edge edges edge =
let (src, dst, _) = edge in
let rec iter edges res = match edges with
| [] -> res
| ((s, d, _) as e)::edges ->
if (s = src && d = dst) then
res @ edges
else
iter edges (e::res)
in iter edges []
Removing an edge from a graph is then done by building a new graph that shares data with the previous graph, but with a modified list of edges:
let graph_remove_edge graph edge =
{ nodes = graph.nodes;
edges = edges_remove_edge graph.edges edge }
You can then transform the graph along the recursive calls of your graph traversal; the example does nothing interesting here, it is just to demonstrate the structure:
let choose_edge graph = match graph.edges with
| [] -> None
| e::_ -> Some e;;
let rec visit graph = match (choose_edge graph) with
| None -> graph
| Some e -> visit (graph_remove_edge graph e);;
# visit graph;;
- : char graph =
{nodes = ['a'; 'b'; 'c'; 'd'; 'e'; 'f'; 'g'; 'h'; 'j']; edges = []}
Or, you keep track of the current graph with a ref:
let visit2 graph =
let g = ref graph in
let rec v () = match (choose_edge !g) with
| None -> ()
| Some e -> begin g := graph_remove_edge !g e; v () end
in v(); !g