mirror of
https://github.com/ICDSystems/ICD.Common.Utils.git
synced 2026-02-16 05:05:05 +00:00
Adding GetClique and GetCliques recursion methods
This commit is contained in:
@@ -72,6 +72,61 @@ namespace ICD.Common.Utils.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly Dictionary<int, IEnumerable<int>> s_CliqueGraph = new Dictionary<int, IEnumerable<int>>
|
||||||
|
{
|
||||||
|
{1, new[] {2, 3}},
|
||||||
|
{2, new[] {1, 4}},
|
||||||
|
{3, new[] {1}},
|
||||||
|
{4, new[] {2}},
|
||||||
|
{5, new[] {6}},
|
||||||
|
{6, new[] {5}}
|
||||||
|
};
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetCliquesTest()
|
||||||
|
{
|
||||||
|
int[][] cliques =
|
||||||
|
RecursionUtils.GetCliques(s_CliqueGraph.Keys, i => s_CliqueGraph[i])
|
||||||
|
.Select(c => c.ToArray())
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
Assert.AreEqual(2, cliques.Length);
|
||||||
|
|
||||||
|
int[] clique1 = cliques.FirstOrDefault(c => c.Contains(1));
|
||||||
|
int[] clique2 = cliques.FirstOrDefault(c => c != clique1);
|
||||||
|
|
||||||
|
Assert.NotNull(clique1);
|
||||||
|
Assert.NotNull(clique2);
|
||||||
|
|
||||||
|
Assert.AreEqual(4, clique1.Length);
|
||||||
|
Assert.IsTrue(clique1.Contains(1));
|
||||||
|
Assert.IsTrue(clique1.Contains(2));
|
||||||
|
Assert.IsTrue(clique1.Contains(3));
|
||||||
|
Assert.IsTrue(clique1.Contains(4));
|
||||||
|
|
||||||
|
Assert.AreEqual(2, clique2.Length);
|
||||||
|
Assert.IsTrue(clique2.Contains(5));
|
||||||
|
Assert.IsTrue(clique2.Contains(6));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetCliqueTest()
|
||||||
|
{
|
||||||
|
int[] clique = RecursionUtils.GetClique(s_CliqueGraph, 1).ToArray();
|
||||||
|
|
||||||
|
Assert.AreEqual(4, clique.Length);
|
||||||
|
Assert.IsTrue(clique.Contains(1));
|
||||||
|
Assert.IsTrue(clique.Contains(2));
|
||||||
|
Assert.IsTrue(clique.Contains(3));
|
||||||
|
Assert.IsTrue(clique.Contains(4));
|
||||||
|
|
||||||
|
clique = RecursionUtils.GetClique(s_CliqueGraph, 5).ToArray();
|
||||||
|
|
||||||
|
Assert.AreEqual(2, clique.Length);
|
||||||
|
Assert.IsTrue(clique.Contains(5));
|
||||||
|
Assert.IsTrue(clique.Contains(6));
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void BreadthFirstSearchTest()
|
public void BreadthFirstSearchTest()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,11 +3,90 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using ICD.Common.Properties;
|
using ICD.Common.Properties;
|
||||||
using ICD.Common.Utils.Collections;
|
using ICD.Common.Utils.Collections;
|
||||||
|
using ICD.Common.Utils.Extensions;
|
||||||
|
|
||||||
namespace ICD.Common.Utils
|
namespace ICD.Common.Utils
|
||||||
{
|
{
|
||||||
public static class RecursionUtils
|
public static class RecursionUtils
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a sequence of the cliques in the graph.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="nodes"></param>
|
||||||
|
/// <param name="getAdjacent"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IEnumerable<IEnumerable<T>> GetCliques<T>(IEnumerable<T> nodes, Func<T, IEnumerable<T>> getAdjacent)
|
||||||
|
{
|
||||||
|
if (nodes == null)
|
||||||
|
throw new ArgumentNullException("nodes");
|
||||||
|
|
||||||
|
if (getAdjacent == null)
|
||||||
|
throw new ArgumentNullException("getAdjacent");
|
||||||
|
|
||||||
|
Dictionary<T, IEnumerable<T>> map = nodes.ToDictionary(n => n, getAdjacent);
|
||||||
|
IcdHashSet<T> visited = new IcdHashSet<T>();
|
||||||
|
|
||||||
|
return map.Keys
|
||||||
|
.Where(n => !visited.Contains(n))
|
||||||
|
.Select(node => GetClique(map, visited, node));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the clique containing the given node.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <param name="map"></param>
|
||||||
|
/// <param name="node"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IEnumerable<T> GetClique<T>(IDictionary<T, IEnumerable<T>> map, T node)
|
||||||
|
{
|
||||||
|
if (map == null)
|
||||||
|
throw new ArgumentNullException("map");
|
||||||
|
|
||||||
|
// ReSharper disable once CompareNonConstrainedGenericWithNull
|
||||||
|
if (node == null)
|
||||||
|
throw new ArgumentNullException("node");
|
||||||
|
|
||||||
|
return GetClique(map, new IcdHashSet<T>(), 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> GetClique<T>(IDictionary<T, IEnumerable<T>> map, IcdHashSet<T> visited, T node)
|
||||||
|
{
|
||||||
|
if (map == null)
|
||||||
|
throw new ArgumentNullException("map");
|
||||||
|
|
||||||
|
if (visited == null)
|
||||||
|
throw new ArgumentNullException("visited");
|
||||||
|
|
||||||
|
// ReSharper disable once CompareNonConstrainedGenericWithNull
|
||||||
|
if (node == null)
|
||||||
|
throw new ArgumentNullException("node");
|
||||||
|
|
||||||
|
if (visited.Contains(node))
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
if (!map.ContainsKey(node))
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
visited.Add(node);
|
||||||
|
|
||||||
|
yield return node;
|
||||||
|
|
||||||
|
IEnumerable<T> adjacent = map.GetDefault(node, Enumerable.Empty<T>());
|
||||||
|
|
||||||
|
foreach (T item in adjacent.SelectMany(a => GetClique(map, visited, a)))
|
||||||
|
yield return item;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns all of the nodes in the tree via breadth-first search.
|
/// Returns all of the nodes in the tree via breadth-first search.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user