How to sort depended objects by dependency

后端 未结 10 544
青春惊慌失措
青春惊慌失措 2020-11-28 19:31

I have a collection:

List> dependencyHierarchy;

The first item in pair is some object (item) and the

10条回答
  •  时光取名叫无心
    2020-11-28 19:58

    I don't like recursive methods so DMM is out. Krumelur looks good but seems to use a lot of memory? Made an alternative stack based method that seems to work. Uses same DFS logic as DMM 's and I used this solutions as comparison when testing.

        public static IEnumerable TopogicalSequenceDFS(this IEnumerable source, Func> deps)
        {
            HashSet yielded = new HashSet();
            HashSet visited = new HashSet();
            Stack>> stack = new Stack>>();
    
            foreach (T t in source)
            {
                stack.Clear();
                if (visited.Add(t))
                    stack.Push(new Tuple>(t, deps(t).GetEnumerator()));
    
                while (stack.Count > 0)
                {
                    var p = stack.Peek();
                    bool depPushed = false;
                    while (p.Item2.MoveNext())
                    {
                        var curr = p.Item2.Current;
                        if (visited.Add(curr))
                        {
                            stack.Push(new Tuple>(curr, deps(curr).GetEnumerator()));
                            depPushed = true;
                            break;
                        }
                        else if (!yielded.Contains(curr))
                            throw new Exception("cycle");
                    }
    
                    if (!depPushed)
                    {
                        p = stack.Pop();
                        if (!yielded.Add(p.Item1))
                            throw new Exception("bug");
                        yield return p.Item1;
                    }
                }
            }
        }
    

    Here is also a simpler stack based BFS variant. It will produce different result than the above, but still valid. I'm not sure if there is any advantage to using the DFS variant above, but it was fun creating it.

        public static IEnumerable TopologicalSequenceBFS(this IEnumerable source, Func> dependencies)
        {
            var yielded = new HashSet();
            var visited = new HashSet();
            var stack = new Stack>(source.Select(s => new Tuple(s, false))); // bool signals Add to sorted
    
            while (stack.Count > 0)
            {
                var item = stack.Pop();
                if (!item.Item2)
                {
                    if (visited.Add(item.Item1))
                    {
                        stack.Push(new Tuple(item.Item1, true)); // To be added after processing the dependencies
                        foreach (var dep in dependencies(item.Item1))
                            stack.Push(new Tuple(dep, false));
                    }
                    else if (!yielded.Contains(item.Item1))
                        throw new Exception("cyclic");
                }
                else
                {
                    if (!yielded.Add(item.Item1))
                        throw new Exception("bug");
                    yield return item.Item1;
                }
            }
        }
    

    For .NET 4.7+ I suggest replacing Tuple with ValueTuple for lower memory use. In older .NET versions Tuple can be replaced with KeyValuePair.

提交回复
热议问题