/// <summary> /// The actual crawler routine. It visits the specified vertex over the edge used. If the vertex is visitable over multiple edges from the last visited vertex, /// the routine is called multiple times. /// </summary> /// <param name="vertex">The vertex.</param> /// <param name="verticesProcessed">The vertices processed.</param> /// <param name="edges">The edges usable to visit the vertex.</param> private void Visit(TVertex vertex, IDictionary <TVertex, VertexColor> verticesProcessed, HashSet <TEdge> edges) { if (_abortCrawl) { return; } if (!verticesProcessed.ContainsKey(vertex)) { verticesProcessed.Add(vertex, VertexColor.NotVisited); } if (verticesProcessed[vertex] == VertexColor.Visiting) { // check if we ran into a cycle, in the case of a directed graph if (_graphToCrawl.IsDirected) { if (_detectCycles) { // cycle detected, as we're reaching a vertex (via recursion) which is still in progress. It depends on the CycleDetected routine if we may // proceed. bool continueTraverse = CycleDetected(vertex, edges); if (!continueTraverse) { // simply break off traversal. return; } } } else { // as the crawler visits vertices over all the edges at once, in an undirected graph there is no such situation where the visited vertex // has more edges to the previous vertex as the previous vertex has to the currently visited vertex. // break off traversal return; } } if (verticesProcessed[vertex] == VertexColor.Visited) { // vertex has already been processed return; } verticesProcessed[vertex] = VertexColor.Visiting; MultiValueDictionary <TVertex, TEdge> adjacencyList = _graphToCrawl.GetAdjacencyListForVertex(vertex); OnVisiting(vertex, edges); // crawl to all this vertex' related vertices, if they've not yet been processed. foreach (KeyValuePair <TVertex, HashSet <TEdge> > relatedVertexEdgesTuple in adjacencyList) { if (_abortCrawl) { break; } // recurse to the related vertex, over the edges in the list of edges. We simply pass the whole hashset as it doesn't matter which edge is picked // to crawl the graph, but an algorithm might want to know which edges to pick from, so it's better to pass them as a whole than to pass them one by // one in a non-sequential order (through backtracking) Visit(relatedVertexEdgesTuple.Key, verticesProcessed, relatedVertexEdgesTuple.Value); } OnVisited(vertex, edges); verticesProcessed[vertex] = VertexColor.Visited; }