mirror of
https://github.com/ICDSystems/ICD.Common.Utils.git
synced 2026-01-11 19:44:55 +00:00
feat: Added breadth-first search method that returns the path from root for every node in the graph
This commit is contained in:
@@ -250,5 +250,40 @@ namespace ICD.Common.Utils.Tests
|
|||||||
Assert.AreEqual(6, paths[62].ToArray()[1]);
|
Assert.AreEqual(6, paths[62].ToArray()[1]);
|
||||||
Assert.AreEqual(62, paths[62].ToArray()[2]);
|
Assert.AreEqual(62, paths[62].ToArray()[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void BreadthFirstSearchPathsTest()
|
||||||
|
{
|
||||||
|
Dictionary<int, IEnumerable<int>> paths =
|
||||||
|
RecursionUtils.BreadthFirstSearchPaths(1, Graph)
|
||||||
|
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||||
|
|
||||||
|
// Verify we visited all destinations
|
||||||
|
Assert.AreEqual(4, paths.Count);
|
||||||
|
Assert.IsTrue(paths.ContainsKey(1));
|
||||||
|
Assert.IsTrue(paths.ContainsKey(2));
|
||||||
|
Assert.IsTrue(paths.ContainsKey(3));
|
||||||
|
Assert.IsTrue(paths.ContainsKey(4));
|
||||||
|
|
||||||
|
// Verify path for destination 1
|
||||||
|
Assert.AreEqual(1, paths[1].ToArray().Length);
|
||||||
|
Assert.AreEqual(1, paths[1].ToArray()[0]);
|
||||||
|
|
||||||
|
// Verify path for destination 2
|
||||||
|
Assert.AreEqual(2, paths[2].ToArray().Length);
|
||||||
|
Assert.AreEqual(1, paths[2].ToArray()[0]);
|
||||||
|
Assert.AreEqual(2, paths[2].ToArray()[1]);
|
||||||
|
|
||||||
|
// Verify path for destination 3
|
||||||
|
Assert.AreEqual(2, paths[3].ToArray().Length);
|
||||||
|
Assert.AreEqual(1, paths[3].ToArray()[0]);
|
||||||
|
Assert.AreEqual(3, paths[3].ToArray()[1]);
|
||||||
|
|
||||||
|
// Verify path for destination 4
|
||||||
|
Assert.AreEqual(3, paths[4].ToArray().Length);
|
||||||
|
Assert.AreEqual(1, paths[4].ToArray()[0]);
|
||||||
|
Assert.AreEqual(2, paths[4].ToArray()[1]);
|
||||||
|
Assert.AreEqual(4, paths[4].ToArray()[2]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ namespace ICD.Common.Utils
|
|||||||
/// <param name="nodes"></param>
|
/// <param name="nodes"></param>
|
||||||
/// <param name="getAdjacent"></param>
|
/// <param name="getAdjacent"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static IEnumerable<IEnumerable<T>> GetCliques<T>(IEnumerable<T> nodes, Func<T, IEnumerable<T>> getAdjacent)
|
[NotNull]
|
||||||
|
public static IEnumerable<IEnumerable<T>> GetCliques<T>([NotNull] IEnumerable<T> nodes,
|
||||||
|
[NotNull] Func<T, IEnumerable<T>> getAdjacent)
|
||||||
{
|
{
|
||||||
if (nodes == null)
|
if (nodes == null)
|
||||||
throw new ArgumentNullException("nodes");
|
throw new ArgumentNullException("nodes");
|
||||||
@@ -39,7 +41,8 @@ namespace ICD.Common.Utils
|
|||||||
/// <param name="node"></param>
|
/// <param name="node"></param>
|
||||||
/// <param name="getAdjacent"></param>
|
/// <param name="getAdjacent"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static IEnumerable<T> GetClique<T>(T node, Func<T, IEnumerable<T>> getAdjacent)
|
[NotNull]
|
||||||
|
public static IEnumerable<T> GetClique<T>([NotNull] T node, [NotNull] Func<T, IEnumerable<T>> getAdjacent)
|
||||||
{
|
{
|
||||||
if (node == null)
|
if (node == null)
|
||||||
throw new ArgumentNullException("node");
|
throw new ArgumentNullException("node");
|
||||||
@@ -57,7 +60,8 @@ namespace ICD.Common.Utils
|
|||||||
/// <param name="map"></param>
|
/// <param name="map"></param>
|
||||||
/// <param name="node"></param>
|
/// <param name="node"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static IEnumerable<T> GetClique<T>(IDictionary<T, IEnumerable<T>> map, T node)
|
[NotNull]
|
||||||
|
public static IEnumerable<T> GetClique<T>([NotNull] IDictionary<T, IEnumerable<T>> map, [NotNull] T node)
|
||||||
{
|
{
|
||||||
if (map == null)
|
if (map == null)
|
||||||
throw new ArgumentNullException("map");
|
throw new ArgumentNullException("map");
|
||||||
@@ -77,7 +81,8 @@ namespace ICD.Common.Utils
|
|||||||
/// <param name="visited"></param>
|
/// <param name="visited"></param>
|
||||||
/// <param name="node"></param>
|
/// <param name="node"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private static IEnumerable<T> GetClique<T>(IDictionary<T, IEnumerable<T>> map, IcdHashSet<T> visited, T node)
|
private static IEnumerable<T> GetClique<T>([NotNull] IDictionary<T, IEnumerable<T>> map,
|
||||||
|
[NotNull] IcdHashSet<T> visited, [NotNull] T node)
|
||||||
{
|
{
|
||||||
if (map == null)
|
if (map == null)
|
||||||
throw new ArgumentNullException("map");
|
throw new ArgumentNullException("map");
|
||||||
@@ -89,19 +94,6 @@ namespace ICD.Common.Utils
|
|||||||
if (node == null)
|
if (node == null)
|
||||||
throw new ArgumentNullException("node");
|
throw new ArgumentNullException("node");
|
||||||
|
|
||||||
return GetCliqueIterator(map, visited, node);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the clique containing the node.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <param name="map"></param>
|
|
||||||
/// <param name="visited"></param>
|
|
||||||
/// <param name="node"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static IEnumerable<T> GetCliqueIterator<T>(IDictionary<T, IEnumerable<T>> map, IcdHashSet<T> visited, T node)
|
|
||||||
{
|
|
||||||
if (!visited.Add(node))
|
if (!visited.Add(node))
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
@@ -123,8 +115,19 @@ namespace ICD.Common.Utils
|
|||||||
/// <param name="destination"></param>
|
/// <param name="destination"></param>
|
||||||
/// <param name="getChildren"></param>
|
/// <param name="getChildren"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool BreadthFirstSearch<T>(T root, T destination, Func<T, IEnumerable<T>> getChildren)
|
public static bool BreadthFirstSearch<T>([NotNull] T root, [NotNull] T destination,
|
||||||
|
[NotNull] Func<T, IEnumerable<T>> getChildren)
|
||||||
{
|
{
|
||||||
|
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||||
|
if (root == null)
|
||||||
|
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||||
|
throw new ArgumentNullException("root");
|
||||||
|
|
||||||
|
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||||
|
if (destination == null)
|
||||||
|
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||||
|
throw new ArgumentNullException("destination");
|
||||||
|
|
||||||
if (getChildren == null)
|
if (getChildren == null)
|
||||||
throw new ArgumentNullException("getChildren");
|
throw new ArgumentNullException("getChildren");
|
||||||
|
|
||||||
@@ -140,8 +143,20 @@ namespace ICD.Common.Utils
|
|||||||
/// <param name="getChildren"></param>
|
/// <param name="getChildren"></param>
|
||||||
/// <param name="comparer"></param>
|
/// <param name="comparer"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool BreadthFirstSearch<T>(T root, T destination, Func<T, IEnumerable<T>> getChildren, IEqualityComparer<T> comparer)
|
public static bool BreadthFirstSearch<T>([NotNull] T root, [NotNull] T destination,
|
||||||
|
[NotNull] Func<T, IEnumerable<T>> getChildren,
|
||||||
|
[NotNull] IEqualityComparer<T> comparer)
|
||||||
{
|
{
|
||||||
|
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||||
|
if (root == null)
|
||||||
|
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||||
|
throw new ArgumentNullException("root");
|
||||||
|
|
||||||
|
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||||
|
if (destination == null)
|
||||||
|
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||||
|
throw new ArgumentNullException("destination");
|
||||||
|
|
||||||
if (getChildren == null)
|
if (getChildren == null)
|
||||||
throw new ArgumentNullException("getChildren");
|
throw new ArgumentNullException("getChildren");
|
||||||
|
|
||||||
@@ -158,38 +173,17 @@ namespace ICD.Common.Utils
|
|||||||
/// <param name="root"></param>
|
/// <param name="root"></param>
|
||||||
/// <param name="getChildren"></param>
|
/// <param name="getChildren"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static IEnumerable<T> BreadthFirstSearch<T>(T root, Func<T, IEnumerable<T>> getChildren)
|
public static IEnumerable<T> BreadthFirstSearch<T>([NotNull] T root, [NotNull] Func<T, IEnumerable<T>> getChildren)
|
||||||
{
|
{
|
||||||
|
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||||
|
if (root == null)
|
||||||
|
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||||
|
throw new ArgumentNullException("root");
|
||||||
|
|
||||||
if (getChildren == null)
|
if (getChildren == null)
|
||||||
throw new ArgumentNullException("getChildren");
|
throw new ArgumentNullException("getChildren");
|
||||||
|
|
||||||
return BreadthFirstSearchIterator(root, getChildren);
|
return BreadthFirstSearchPaths(root, getChildren, EqualityComparer<T>.Default).Select(kvp => kvp.Key);
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns all of the nodes in the graph via breadth-first search.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T"></typeparam>
|
|
||||||
/// <param name="root"></param>
|
|
||||||
/// <param name="getChildren"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static IEnumerable<T> BreadthFirstSearchIterator<T>(T root, Func<T, IEnumerable<T>> getChildren)
|
|
||||||
{
|
|
||||||
IcdHashSet<T> visited = new IcdHashSet<T> {root};
|
|
||||||
Queue<T> process = new Queue<T>();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -201,8 +195,19 @@ namespace ICD.Common.Utils
|
|||||||
/// <param name="getChildren"></param>
|
/// <param name="getChildren"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
public static IEnumerable<T> BreadthFirstSearchPath<T>(T root, T destination, Func<T, IEnumerable<T>> getChildren)
|
public static IEnumerable<T> BreadthFirstSearchPath<T>([NotNull] T root, [NotNull] T destination,
|
||||||
|
[NotNull] Func<T, IEnumerable<T>> getChildren)
|
||||||
{
|
{
|
||||||
|
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||||
|
if (root == null)
|
||||||
|
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||||
|
throw new ArgumentNullException("root");
|
||||||
|
|
||||||
|
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||||
|
if (destination == null)
|
||||||
|
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||||
|
throw new ArgumentNullException("destination");
|
||||||
|
|
||||||
if (getChildren == null)
|
if (getChildren == null)
|
||||||
throw new ArgumentNullException("getChildren");
|
throw new ArgumentNullException("getChildren");
|
||||||
|
|
||||||
@@ -219,42 +224,29 @@ namespace ICD.Common.Utils
|
|||||||
/// <param name="comparer"></param>
|
/// <param name="comparer"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
public static IEnumerable<T> BreadthFirstSearchPath<T>(T root, T destination, Func<T, IEnumerable<T>> getChildren,
|
public static IEnumerable<T> BreadthFirstSearchPath<T>([NotNull] T root, [NotNull] T destination,
|
||||||
IEqualityComparer<T> comparer)
|
[NotNull] Func<T, IEnumerable<T>> getChildren,
|
||||||
|
[NotNull] IEqualityComparer<T> comparer)
|
||||||
{
|
{
|
||||||
|
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||||
|
if (root == null)
|
||||||
|
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||||
|
throw new ArgumentNullException("root");
|
||||||
|
|
||||||
|
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||||
|
if (destination == null)
|
||||||
|
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||||
|
throw new ArgumentNullException("destination");
|
||||||
|
|
||||||
if (getChildren == null)
|
if (getChildren == null)
|
||||||
throw new ArgumentNullException("getChildren");
|
throw new ArgumentNullException("getChildren");
|
||||||
|
|
||||||
if (comparer == null)
|
if (comparer == null)
|
||||||
throw new ArgumentNullException("comparer");
|
throw new ArgumentNullException("comparer");
|
||||||
|
|
||||||
// Edge case - root and destination are the same
|
return BreadthFirstSearchPathManyDestinations(root, destination.Yield(), getChildren, comparer)
|
||||||
if (comparer.Equals(root, destination))
|
.Select(kvp => kvp.Value)
|
||||||
return new[] {root};
|
.FirstOrDefault();
|
||||||
|
|
||||||
Queue<T> queue = new Queue<T>();
|
|
||||||
queue.Enqueue(root);
|
|
||||||
|
|
||||||
Dictionary<T, T> nodeParents = new Dictionary<T, T>(comparer);
|
|
||||||
|
|
||||||
T current;
|
|
||||||
while (queue.Dequeue(out current))
|
|
||||||
{
|
|
||||||
foreach (T node in getChildren(current))
|
|
||||||
{
|
|
||||||
if (nodeParents.ContainsKey(node))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
queue.Enqueue(node);
|
|
||||||
nodeParents.Add(node, current);
|
|
||||||
|
|
||||||
// Found a path to the destination
|
|
||||||
if (comparer.Equals(node, destination))
|
|
||||||
return GetPath(destination, root, nodeParents, comparer).Reverse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -265,9 +257,16 @@ namespace ICD.Common.Utils
|
|||||||
/// <param name="destinations"></param>
|
/// <param name="destinations"></param>
|
||||||
/// <param name="getChildren"></param>
|
/// <param name="getChildren"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
[NotNull]
|
||||||
public static IEnumerable<KeyValuePair<T, IEnumerable<T>>>
|
public static IEnumerable<KeyValuePair<T, IEnumerable<T>>>
|
||||||
BreadthFirstSearchPathManyDestinations<T>(T root, IEnumerable<T> destinations, Func<T, IEnumerable<T>> getChildren)
|
BreadthFirstSearchPathManyDestinations<T>([NotNull] T root, [NotNull] IEnumerable<T> destinations,
|
||||||
|
[NotNull] Func<T, IEnumerable<T>> getChildren)
|
||||||
{
|
{
|
||||||
|
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||||
|
if (root == null)
|
||||||
|
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||||
|
throw new ArgumentNullException("root");
|
||||||
|
|
||||||
if (destinations == null)
|
if (destinations == null)
|
||||||
throw new ArgumentNullException("destinations");
|
throw new ArgumentNullException("destinations");
|
||||||
|
|
||||||
@@ -286,10 +285,17 @@ namespace ICD.Common.Utils
|
|||||||
/// <param name="getChildren"></param>
|
/// <param name="getChildren"></param>
|
||||||
/// <param name="comparer"></param>
|
/// <param name="comparer"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
|
[NotNull]
|
||||||
public static IEnumerable<KeyValuePair<T, IEnumerable<T>>>
|
public static IEnumerable<KeyValuePair<T, IEnumerable<T>>>
|
||||||
BreadthFirstSearchPathManyDestinations<T>(T root, IEnumerable<T> destinations, Func<T, IEnumerable<T>> getChildren,
|
BreadthFirstSearchPathManyDestinations<T>([NotNull] T root, [NotNull] IEnumerable<T> destinations,
|
||||||
IEqualityComparer<T> comparer)
|
[NotNull] Func<T, IEnumerable<T>> getChildren,
|
||||||
|
[NotNull] IEqualityComparer<T> comparer)
|
||||||
{
|
{
|
||||||
|
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||||
|
if (root == null)
|
||||||
|
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||||
|
throw new ArgumentNullException("root");
|
||||||
|
|
||||||
if (destinations == null)
|
if (destinations == null)
|
||||||
throw new ArgumentNullException("destinations");
|
throw new ArgumentNullException("destinations");
|
||||||
|
|
||||||
@@ -299,23 +305,68 @@ namespace ICD.Common.Utils
|
|||||||
if (comparer == null)
|
if (comparer == null)
|
||||||
throw new ArgumentNullException("comparer");
|
throw new ArgumentNullException("comparer");
|
||||||
|
|
||||||
IcdHashSet<T> destinationsToBeProcessed = new IcdHashSet<T>(destinations);
|
IcdHashSet<T> destinationsSet = destinations as IcdHashSet<T> ?? destinations.ToIcdHashSet();
|
||||||
|
return BreadthFirstSearchPaths(root, getChildren, comparer)
|
||||||
// Edge case, root is the destination
|
.Where(kvp => destinationsSet.Contains(kvp.Key))
|
||||||
foreach (T destination in
|
.Take(destinationsSet.Count);
|
||||||
destinationsToBeProcessed.Where(destination => comparer.Equals(root, destination)).ToArray())
|
|
||||||
{
|
|
||||||
destinationsToBeProcessed.Remove(destination);
|
|
||||||
yield return new KeyValuePair<T, IEnumerable<T>>(destination, new[] {root});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (destinationsToBeProcessed.Count == 0)
|
/// <summary>
|
||||||
yield break;
|
/// Returns the shortest path from root to each destination via breadth-first search.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="root"></param>
|
||||||
|
/// <param name="getChildren"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[NotNull]
|
||||||
|
public static IEnumerable<KeyValuePair<T, IEnumerable<T>>>
|
||||||
|
BreadthFirstSearchPaths<T>([NotNull] T root, [NotNull] Func<T, IEnumerable<T>> getChildren)
|
||||||
|
{
|
||||||
|
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||||
|
if (root == null)
|
||||||
|
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||||
|
throw new ArgumentNullException("root");
|
||||||
|
|
||||||
|
if (getChildren == null)
|
||||||
|
throw new ArgumentNullException("getChildren");
|
||||||
|
|
||||||
|
return BreadthFirstSearchPaths(root, getChildren, EqualityComparer<T>.Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the shortest path from root to each destination via breadth-first search.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="root"></param>
|
||||||
|
/// <param name="getChildren"></param>
|
||||||
|
/// <param name="comparer"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[NotNull]
|
||||||
|
public static IEnumerable<KeyValuePair<T, IEnumerable<T>>>
|
||||||
|
BreadthFirstSearchPaths<T>([NotNull] T root, [NotNull] Func<T, IEnumerable<T>> getChildren,
|
||||||
|
[NotNull] IEqualityComparer<T> 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");
|
||||||
|
|
||||||
|
// Edge case - root is the same as destination
|
||||||
|
yield return new KeyValuePair<T, IEnumerable<T>>(root, root.Yield());
|
||||||
|
|
||||||
Queue<T> queue = new Queue<T>();
|
Queue<T> queue = new Queue<T>();
|
||||||
queue.Enqueue(root);
|
queue.Enqueue(root);
|
||||||
|
|
||||||
Dictionary<T, T> nodeParents = new Dictionary<T, T>(comparer);
|
Dictionary<T, T> nodeParents = new Dictionary<T, T>(comparer)
|
||||||
|
{
|
||||||
|
{root, default(T)}
|
||||||
|
};
|
||||||
|
|
||||||
while (queue.Count > 0)
|
while (queue.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -326,18 +377,8 @@ namespace ICD.Common.Utils
|
|||||||
queue.Enqueue(node);
|
queue.Enqueue(node);
|
||||||
nodeParents.Add(node, current);
|
nodeParents.Add(node, current);
|
||||||
|
|
||||||
T closureNode = node;
|
|
||||||
foreach (T destination in
|
|
||||||
destinationsToBeProcessed.Where(destination => comparer.Equals(closureNode, destination)).ToArray())
|
|
||||||
{
|
|
||||||
destinationsToBeProcessed.Remove(destination);
|
|
||||||
|
|
||||||
yield return
|
yield return
|
||||||
new KeyValuePair<T, IEnumerable<T>>(destination, GetPath(destination, root, nodeParents, comparer).Reverse());
|
new KeyValuePair<T, IEnumerable<T>>(node, GetPath(node, root, nodeParents, comparer).Reverse());
|
||||||
}
|
|
||||||
|
|
||||||
if (destinationsToBeProcessed.Count == 0)
|
|
||||||
yield break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -351,8 +392,26 @@ namespace ICD.Common.Utils
|
|||||||
/// <param name="nodeParents"></param>
|
/// <param name="nodeParents"></param>
|
||||||
/// <param name="comparer"></param>
|
/// <param name="comparer"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private static IEnumerable<T> GetPath<T>(T start, T end, IDictionary<T, T> nodeParents, IEqualityComparer<T> comparer)
|
[NotNull]
|
||||||
|
private static IEnumerable<T> GetPath<T>([NotNull] T start, [NotNull] T end, [NotNull] IDictionary<T, T> nodeParents,
|
||||||
|
[NotNull] IEqualityComparer<T> comparer)
|
||||||
{
|
{
|
||||||
|
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||||
|
if (start == null)
|
||||||
|
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||||
|
throw new ArgumentNullException("start");
|
||||||
|
|
||||||
|
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||||
|
if (end == null)
|
||||||
|
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||||
|
throw new ArgumentNullException("end");
|
||||||
|
|
||||||
|
if (nodeParents == null)
|
||||||
|
throw new ArgumentNullException("nodeParents");
|
||||||
|
|
||||||
|
if (comparer == null)
|
||||||
|
throw new ArgumentNullException("comparer");
|
||||||
|
|
||||||
IcdHashSet<T> visited = new IcdHashSet<T>();
|
IcdHashSet<T> visited = new IcdHashSet<T>();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
@@ -368,6 +427,11 @@ namespace ICD.Common.Utils
|
|||||||
if (!nodeParents.TryGetValue(start, out next))
|
if (!nodeParents.TryGetValue(start, out next))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// ReSharper disable CompareNonConstrainedGenericWithNull
|
||||||
|
if (next == null)
|
||||||
|
// ReSharper restore CompareNonConstrainedGenericWithNull
|
||||||
|
break;
|
||||||
|
|
||||||
if (visited.Contains(next))
|
if (visited.Contains(next))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user