/// <summary> /// Get an <see cref="IEnumerable{T}"/> with order of depth-first-search. /// </summary> /// <typeparam name="T">The type of vertex.</typeparam> /// <param name="graph">The graph to enumerate.</param> /// <param name="root">The first vertex to enumerate.</param> /// <returns>An <see cref="IEnumerable{T}"/> with order of depth-first-search.</returns> /// <exception cref="ArgumentNullException">When <paramref name="graph"/> is <see langword="null"/>.</exception> /// <exception cref="KeyNotFoundException">When <paramref name="root"/> is not contained in the graph.</exception> public static IEnumerable <T> AsDFSEnumerable <T>(this IGraph <T> graph, T root) { if (graph == null) { throw ExceptionHelper.ArgumentNull(nameof(graph)); } if (!graph.Contains(root)) { throw ExceptionHelper.KeyNotFound(); } return(AsDFSEnumerableIterator(graph, root)); }
/// <summary> /// Determines whether a vertex is in a loop of an instance of <see cref="IGraph{T}"/>. /// </summary> /// <typeparam name="T">The type of vertex.</typeparam> /// <param name="graph">The graph to enumerate.</param> /// <param name="vertex">The specified vertex.</param> /// <returns><see langword="true"/> if the <paramref name="vertex"/> is in a loop; otherwise, <see langword="false"/>.</returns> /// <exception cref="ArgumentNullException">When <paramref name="graph"/> is <see langword="null"/>.</exception> /// <exception cref="KeyNotFoundException">When <paramref name="vertex"/> is not contained in the graph.</exception> public static bool IsInLoop <T>(this IGraph <T> graph, T vertex) { if (graph == null) { throw ExceptionHelper.ArgumentNull(nameof(graph)); } if (!graph.Contains(vertex)) { throw ExceptionHelper.KeyNotFound(); } Stack <T> nodes = new Stack <T>(); HashSet <T> visited = new HashSet <T>(); nodes.Push(vertex); T last = default; while (nodes.Count != 0) { T current; do { if (nodes.Count == 0) { goto ret; } current = nodes.Pop(); }while (visited.Contains(current)); visited.Add(current); if (graph.TryGetHeads(current, out var heads)) { foreach (var child in heads) { if (!visited.Contains(child)) { nodes.Push(child); } else if (EqualityComparer <T> .Default.Equals(vertex, child) && !EqualityComparer <T> .Default.Equals(last, child)) { return(true); } } } last = current; } ret: return(false); }