public static IGraphNavigator BFSpanningTree(IEnumerable roots, IGraphNavigator navigator, DNodePredicate avoid) { BFSpanningBuilder bfb = new BFSpanningBuilder(); bfs(roots, navigator, avoid, null, new DEdgeVisitor(bfb.VisitEdge)); return bfb; }
/// <summary> /// Does a breadth first traversal of the given graph /// </summary> /// <param name="roots">The roots of the traversal.</param> /// <param name="avoid">If not null, is a predicate to avoid certain nodes</param> /// <param name="visitRoot">If not null, called for each root that is not avoided.</param> /// <param name="visitEdge">Called for each edges in the bf traversal, i.e., only for edges going to unvisited nodes.</param> public static void bfs(IEnumerable roots, IGraphNavigator navigator, DNodePredicate avoid, DNodeVisitor visitRoot, DEdgeVisitor visitEdge) { Queue queue = new Queue(); IMutableSet seen = new HashSet(); // initialize queue with roots foreach(object o in roots) { if (avoid==null || !avoid(o)) { queue.Enqueue(o); seen.Add(o); if (visitRoot != null) visitRoot(o); } } while(queue.Count > 0) { object node = queue.Dequeue(); foreach(object succ in navigator.NextNodes(node)) { if ((avoid == null || !avoid(succ)) && !seen.Contains(succ)) { seen.Add(succ); queue.Enqueue(succ); visitEdge(node, succ); } } } }
/// <summary> /// DFS traversal of the (sub)graph rooted in a set of nodes. /// </summary> /// <param name="roots">Roots of the traversed subgraph. The subgraph /// rooted in the first root will be traversed in DFS order; next, if /// the second root wasn't reached yet, the subgraph rooted in it will /// be traversed in DFS order and so on. The order of /// the roots is given by the corresponding <c>IEnumerator</c>.</param> /// <param name="navigator">Navigator that describes the graph structure.</param> /// <param name="avoid">Encountered nodes that satisfy this predicate will be /// ignored by the DFS traversal (together with their attached arcs). <c>null</c> /// corresponds to the predicate that is always false (i.e., no encountered node /// will be ignored).</param> /// <param name="new_subgraph_visitor">Visitor for the root node of each /// new subgraph: the roots (see the roots parameter) /// are explored in order; if a root node has not been already reached /// by the DFS traversal of the previous roots, <c>new_subgraph_visitor</c> /// will be called on it, and next the subgraph rooted in it will be DFS /// traversed.</param> /// <param name="begin_visitor">Node visitor to be called when a node is reached /// for the first time by the DFS traversal. <c>null</c> corresponds to no /// visitor.</param> /// <param name="end_visitor">Node visitor to be called when the exploration of /// a node has finished. <c>null</c> corresponds to no visitor.</param> public static void SearchDepthFirst ( IEnumerable roots, IGraphNavigator navigator, DNodePredicate avoid, DNodeVisitor new_subgraph_visitor, DNodeVisitor begin_visitor, DNodeVisitor end_visitor ) { // set of already seen nodes IMutableSet seen_nodes = new HashSet(); // DFS Stack: holds the currently explored path; simulates the call // stack of a recursive implementation of DFS. Stack/*<NodeInfo>*/ stack = new Stack(); foreach(object root in roots) { if( ((avoid != null) && avoid(root)) || seen_nodes.Contains(root)) continue; call_visitor(new_subgraph_visitor, root); seen_nodes.Add(root); call_visitor(begin_visitor, root); stack.Push(new NodeInfo(root, navigator)); while(stack.Count != 0) { NodeInfo info = (NodeInfo) stack.Peek(); if(info.enext.MoveNext()) { object next_node = info.enext.Current; // ignore nodes as dictated by "avoid" if((avoid != null) && avoid(next_node)) continue; if(!seen_nodes.Contains(next_node)) { // new and non-avoidable node! // mark it as seen, seen_nodes.Add(next_node); // call the begin visitor, call_visitor(begin_visitor, next_node); // and put the node on the DFS stack stack.Push(new NodeInfo(next_node, navigator)); } } else { // the visit of info.node has finished // apply end visitor call_visitor(end_visitor, info.node); // remove the top of the stack stack.Pop(); } } } }
/// <summary> /// Convenient <c>DFS</c> function. Call the full <c>dfs</c> function /// with new_subgraph_visitor set to <c>null</c>. /// </summary> public static void dfs ( IEnumerable roots, IGraphNavigator navigator, DNodePredicate avoid, DNodeVisitor begin_visitor, DNodeVisitor end_visitor) { SearchDepthFirst(roots, navigator, avoid, null, begin_visitor, end_visitor); }
public static ISet ReachableNodes (DSetFactory setfactory, IEnumerable roots, IGraphNavigator navigator, DNodePredicate avoid) { ReachableNodesData data = new ReachableNodesData(setfactory); SearchDepthFirst(roots, navigator, avoid, null, new DNodeVisitor(data.reachable_visitor), null); return data.all_nodes; }