diff --git a/CHANGELOG.md b/CHANGELOG.md index e10ace8..5d82b80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added - Added RecursionUtils method to get a single clique given a starting node + - Breadth First Search can now search graphs in addition to trees ### Changed - Fixed bug in IcdUriBuilder where Query property behaved differently to UriBuilder diff --git a/ICD.Common.Utils.Tests/RecursionUtilsTest.cs b/ICD.Common.Utils.Tests/RecursionUtilsTest.cs index e50e025..ff96110 100644 --- a/ICD.Common.Utils.Tests/RecursionUtilsTest.cs +++ b/ICD.Common.Utils.Tests/RecursionUtilsTest.cs @@ -130,7 +130,7 @@ namespace ICD.Common.Utils.Tests [Test] public void GetCliqueSingleNodeTest() { - int[] clique = RecursionUtils.GetClique(s_CliqueGraph.Keys, 1, n => s_CliqueGraph[n]).ToArray(); + int[] clique = RecursionUtils.GetClique(1, n => s_CliqueGraph[n]).ToArray(); Assert.AreEqual(4, clique.Length); Assert.IsTrue(clique.Contains(1)); @@ -138,7 +138,7 @@ namespace ICD.Common.Utils.Tests Assert.IsTrue(clique.Contains(3)); Assert.IsTrue(clique.Contains(4)); - clique = RecursionUtils.GetClique(s_CliqueGraph.Keys, 5, n => s_CliqueGraph[n]).ToArray(); + clique = RecursionUtils.GetClique(5, n => s_CliqueGraph[n]).ToArray(); Assert.AreEqual(2, clique.Length); Assert.IsTrue(clique.Contains(5)); diff --git a/ICD.Common.Utils/RecursionUtils.cs b/ICD.Common.Utils/RecursionUtils.cs index 826f35f..ad0e857 100644 --- a/ICD.Common.Utils/RecursionUtils.cs +++ b/ICD.Common.Utils/RecursionUtils.cs @@ -36,14 +36,18 @@ namespace ICD.Common.Utils /// Gets the clique containing the given node. /// /// - /// /// /// /// - public static IEnumerable GetClique(IEnumerable nodes, T node, Func> getAdjacent) + public static IEnumerable GetClique(T node, Func> getAdjacent) { - Dictionary> map = nodes.ToDictionary(n => n, getAdjacent); - return GetClique(map, node); + if (node == null) + throw new ArgumentNullException("node"); + + if (getAdjacent == null) + throw new ArgumentNullException("getAdjacent"); + + return BreadthFirstSearch(node, getAdjacent); } /// @@ -163,7 +167,7 @@ namespace ICD.Common.Utils } /// - /// Returns all of the nodes in the tree via breadth-first search. + /// Returns all of the nodes in the graph via breadth-first search. /// /// /// @@ -171,6 +175,7 @@ namespace ICD.Common.Utils /// private static IEnumerable BreadthFirstSearchIterator(T root, Func> getChildren) { + IcdHashSet visited = new IcdHashSet {root}; Queue process = new Queue(); process.Enqueue(root); @@ -179,8 +184,11 @@ namespace ICD.Common.Utils { yield return current; - foreach (T child in getChildren(current)) + foreach (T child in getChildren(current).Where(c => !visited.Contains(c))) + { + visited.Add(child); process.Enqueue(child); + } } }