/// <summary> /// Enumerates edges of the graph in a breadth-first order. /// </summary> /// <param name="graph">The graph.</param> /// <param name="source">The source.</param> /// <param name="vertexCount">The number of vertices.</param> /// <returns>An enumerator to enumerate the edges of a depth-first search tree.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="graph"/> is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="vertexCount"/> is less than zero. /// </exception> public IEnumerator <TEdge> EnumerateEdges(TGraph graph, int source, int vertexCount) { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } if (vertexCount < 0) { throw new ArgumentOutOfRangeException(nameof(vertexCount)); } if (unchecked ((uint)source >= vertexCount)) { yield break; } byte[] exploredSet = ArrayPool <byte> .Shared.Rent(vertexCount); Array.Clear(exploredSet, 0, exploredSet.Length); var queue = new Internal.Queue <int>(); try { SetHelpers.Add(exploredSet, source); queue.Add(source); while (queue.TryTake(out int u)) { #if DEBUG Debug.Assert(SetHelpers.Contains(exploredSet, u)); #endif TEdgeEnumerator outEdges = graph.EnumerateOutEdges(u); while (outEdges.MoveNext()) { TEdge e = outEdges.Current; if (!graph.TryGetHead(e, out int v)) { continue; } if (SetHelpers.Contains(exploredSet, v)) { continue; } yield return(e); SetHelpers.Add(exploredSet, v); queue.Add(v); } } } finally { // The Dispose call will happen on the original value of the local if it is the argument to a using statement. queue.Dispose(); ArrayPool <byte> .Shared.Return(exploredSet); } }
/// <summary> /// Traverses the graph in a BFS manner starting from the single source. /// </summary> /// <param name="graph">The graph.</param> /// <param name="source">The source.</param> /// <param name="colorMap">The vertex color map.</param> /// <param name="handler"> /// The <see cref="IBfsHandler{TGraph,TVertex,TEdge}"/> implementation to use /// for the actions taken during the graph traversal. /// </param> /// <typeparam name="TColorMap">The type of the vertex color map.</typeparam> /// <typeparam name="THandler">The type of the events handler.</typeparam> /// <exception cref="ArgumentNullException"> /// <paramref name="graph"/> is <see langword="null"/>, /// or <paramref name="colorMap"/> is <see langword="null"/>, /// or <paramref name="handler"/> is <see langword="null"/>. /// </exception> public void Traverse <TColorMap, THandler>( TGraph graph, TVertex source, TColorMap colorMap, THandler handler) where TColorMap : IDictionary <TVertex, Color> where THandler : IBfsHandler <TGraph, TVertex, TEdge> { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } if (colorMap == null) { throw new ArgumentNullException(nameof(colorMap)); } if (handler == null) { throw new ArgumentNullException(nameof(handler)); } var queue = new Internal.Queue <TVertex>(); colorMap[source] = Color.Gray; handler.OnDiscoverVertex(graph, source); queue.Add(source); TraverseCore(graph, queue, colorMap, handler); }
private static void TraverseCore <TColorMap, THandler>( TGraph graph, Internal.Queue <TVertex> queue, TColorMap colorMap, THandler handler) where TColorMap : IDictionary <TVertex, Color> where THandler : IBfsHandler <TGraph, TVertex, TEdge> { Debug.Assert(graph != null, "graph != null"); Debug.Assert(colorMap != null, "colorMap != null"); Debug.Assert(handler != null, "handler != null"); try { while (queue.TryTake(out TVertex u)) { #if DEBUG Debug.Assert(GetColorOrDefault(colorMap, u) != default); #endif handler.OnExamineVertex(graph, u); TEdgeEnumerator outEdges = graph.EnumerateOutEdges(u); while (outEdges.MoveNext()) { TEdge e = outEdges.Current; if (!graph.TryGetHead(e, out TVertex v)) { continue; } handler.OnExamineEdge(graph, e); Color vColor = GetColorOrDefault(colorMap, v); switch (vColor) { case Color.None: case Color.White: handler.OnTreeEdge(graph, e); colorMap[v] = Color.Gray; handler.OnDiscoverVertex(graph, v); queue.Add(v); break; case Color.Gray: handler.OnNonTreeGrayHeadEdge(graph, e); break; case Color.Black: handler.OnNonTreeBlackHeadEdge(graph, e); break; } } colorMap[u] = Color.Black; handler.OnFinishVertex(graph, u); } } finally { // The Dispose call will happen on the original value of the local if it is the argument to a using statement. queue.Dispose(); } }
/// <summary> /// Enumerates vertices of the graph in a breadth-first order starting from the single source. /// </summary> /// <param name="graph">The graph.</param> /// <param name="source">The source.</param> /// <param name="exploredSet">The set of explored vertices.</param> /// <typeparam name="TExploredSet">The type of the set of explored vertices.</typeparam> /// <returns>An enumerator to enumerate the vertices of a breadth-first search tree.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="graph"/> is <see langword="null"/>, /// or <paramref name="exploredSet"/> is <see langword="null"/>. /// </exception> public IEnumerator <TVertex> EnumerateVertices <TExploredSet>( TGraph graph, TVertex source, TExploredSet exploredSet) where TExploredSet : ISet <TVertex> { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } if (exploredSet == null) { throw new ArgumentNullException(nameof(exploredSet)); } var queue = new Internal.Queue <TVertex>(); try { exploredSet.Add(source); yield return(source); queue.Add(source); while (queue.TryTake(out TVertex u)) { #if DEBUG Debug.Assert(exploredSet.Contains(u)); #endif TEdgeEnumerator outEdges = graph.EnumerateOutEdges(u); while (outEdges.MoveNext()) { TEdge e = outEdges.Current; if (!graph.TryGetHead(e, out TVertex v)) { continue; } if (exploredSet.Contains(v)) { continue; } exploredSet.Add(v); yield return(v); queue.Add(v); } } } finally { // The Dispose call will happen on the original value of the local if it is the argument to a using statement. queue.Dispose(); } }
/// <summary> /// Traverses the graph in a BFS manner starting from the multiple sources. /// </summary> /// <param name="graph">The graph.</param> /// <param name="sources">The sources enumerator.</param> /// <param name="colorMap">The vertex color map.</param> /// <param name="handler"> /// The <see cref="IBfsHandler{TGraph,TVertex,TEdge}"/> implementation to use /// for the actions taken during the graph traversal. /// </param> /// <typeparam name="TVertexEnumerator">The type of the vertex enumerator.</typeparam> /// <typeparam name="TColorMap">The type of the vertex color map.</typeparam> /// <typeparam name="THandler">The type of the events handler.</typeparam> /// <exception cref="ArgumentNullException"> /// <paramref name="graph"/> is <see langword="null"/>, /// or <paramref name="sources"/> is <see langword="null"/>, /// or <paramref name="colorMap"/> is <see langword="null"/>, /// or <paramref name="handler"/> is <see langword="null"/>. /// </exception> public void Traverse <TVertexEnumerator, TColorMap, THandler>( TGraph graph, TVertexEnumerator sources, TColorMap colorMap, THandler handler) where TVertexEnumerator : IEnumerator <TVertex> where TColorMap : IDictionary <TVertex, Color> where THandler : IBfsHandler <TGraph, TVertex, TEdge> { if (graph == null) { throw new ArgumentNullException(nameof(graph)); } if (sources == null) { throw new ArgumentNullException(nameof(sources)); } if (colorMap == null) { throw new ArgumentNullException(nameof(colorMap)); } if (handler == null) { throw new ArgumentNullException(nameof(handler)); } var queue = new Internal.Queue <TVertex>(); while (sources.MoveNext()) { TVertex s = sources.Current; colorMap[s] = Color.Gray; handler.OnDiscoverVertex(graph, s); queue.Add(s); } TraverseCore(graph, queue, colorMap, handler); }