Вам нужны две структуры данных:
- A
Dictionary<int, Session>
для быстрого сопоставления идентификаторов сеансам - A
HashSet<Session>
для удержания сеансов, которые все еще обрабатываются
Вы помещаете все в набор sh, затем, пока набор не пуст, вы берете один и начинаете с ним новый кластер, а затем рекурсивно делаете то же самое для его родителей и потомков, а также для кластера. родители и дети.
Кластер также является набором, чтобы не допускать дублирования.
Изменить: быстрая и грязная реализация выглядит примерно так (сложность примерно O(n logn)
:
struct T
{
public int Id, ParentId;
public T(int id, int parentId) { Id = id; ParentId = parentId; }
public override bool Equals(object obj) => obj is T t && Id == t.Id && ParentId == t.ParentId;
public override int GetHashCode() => HashCode.Combine(Id, ParentId);
public static bool operator ==(T left, T right) => left.Equals(right);
public static bool operator !=(T left, T right) => !(left == right);
}
static void Main(string[] _)
{
var input = new[] { new T(0, -1), new T(1, -1), new T(2, 0), new T(3, 2), new T(4, 2), new T(5, 1) };
var inputSet = input.ToHashSet();
var parentLookup = input.ToDictionary(w => w.Id, w => w.ParentId);
var results = new List<List<T>>();
while (inputSet.Any())
{
var val = inputSet.FirstOrDefault(w => w.ParentId == -1);
if (val.ParentId == 0) break; // done
// remove from the active inputs and add to the result cluster
inputSet.Remove(val);
List<T> cluster;
results.Add(cluster = new List<T> { val });
var clusterIds = new HashSet<int> { val.Id };
// add all children for the cluster elements until no more are available
while (true)
{
var children = inputSet.Where(w => clusterIds.Contains(w.ParentId)).ToList();
if (!children.Any()) break;
children.ForEach(w => { inputSet.Remove(w); cluster.Add(w); clusterIds.Add(w.Id); });
}
}
results.ForEach(r => Console.WriteLine($"{string.Join(", ", r.Select(w => w.Id))}"));
}
Результат:
0, 2, 3, 4
1, 5
Онлайн-витрина