From 41d86ecf48a016544d0db6f0d077a7b1fa86779e Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Tue, 10 Nov 2020 13:54:04 -0500 Subject: [PATCH] perf: Adding faster breadth-first search for when paths are not important --- ICD.Common.Utils/RecursionUtils.cs | 46 ++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/ICD.Common.Utils/RecursionUtils.cs b/ICD.Common.Utils/RecursionUtils.cs index a0bca92..a79aac8 100644 --- a/ICD.Common.Utils/RecursionUtils.cs +++ b/ICD.Common.Utils/RecursionUtils.cs @@ -81,6 +81,7 @@ namespace ICD.Common.Utils /// /// /// + [NotNull] private static IEnumerable GetClique([NotNull] IDictionary> map, [NotNull] IcdHashSet visited, [NotNull] T node) { @@ -163,7 +164,7 @@ namespace ICD.Common.Utils if (comparer == null) throw new ArgumentNullException("comparer"); - return BreadthFirstSearchPath(root, destination, getChildren, comparer) != null; + return BreadthFirstSearch(root, getChildren, comparer).Contains(destination, comparer); } /// @@ -173,6 +174,7 @@ namespace ICD.Common.Utils /// /// /// + [NotNull] public static IEnumerable BreadthFirstSearch([NotNull] T root, [NotNull] Func> getChildren) { // ReSharper disable CompareNonConstrainedGenericWithNull @@ -183,7 +185,47 @@ namespace ICD.Common.Utils if (getChildren == null) throw new ArgumentNullException("getChildren"); - return BreadthFirstSearchPaths(root, getChildren, EqualityComparer.Default).Select(kvp => kvp.Key); + return BreadthFirstSearch(root, getChildren, EqualityComparer.Default); + } + + /// + /// Returns all of the nodes in the tree via breadth-first search. + /// + /// + /// + /// + /// + /// + [NotNull] + public static IEnumerable BreadthFirstSearch([NotNull] T root, [NotNull] Func> getChildren, + [NotNull] IEqualityComparer comparer) + { + // ReSharper disable CompareNonConstrainedGenericWithNull + if (root == null) + // ReSharper restore CompareNonConstrainedGenericWithNull + throw new ArgumentNullException("root"); + + if (getChildren == null) + throw new ArgumentNullException("getChildren"); + + if (comparer == null) + throw new ArgumentNullException("comparer"); + + IcdHashSet visited = new IcdHashSet(comparer) {root}; + Queue process = new Queue(); + process.Enqueue(root); + + T current; + while (process.Dequeue(out current)) + { + yield return current; + + foreach (T child in getChildren(current).Where(c => !visited.Contains(c))) + { + visited.Add(child); + process.Enqueue(child); + } + } } ///