C#: Avoid infinite recursion when traversing object graph

后端 未结 6 1951
心在旅途
心在旅途 2020-12-24 03:17

I have an object graph wherein each child object contains a property that refers back to its parent. Are there any good strategies for ignoring the parent references in orde

6条回答
  •  独厮守ぢ
    2020-12-24 04:13

    What a coincidence; this is the topic of my blog this coming Monday. See it for more details. Until then, here's some code to give you an idea of how to do this:

    static IEnumerable Traversal(
        T item,
        Func> children)
    {
        var seen = new HashSet();
        var stack = new Stack();
        seen.Add(item);
        stack.Push(item); 
        yield return item;
        while(stack.Count > 0)
        {
            T current = stack.Pop();
            foreach(T newItem in children(current))
            {
                if (!seen.Contains(newItem))
                {
                    seen.Add(newItem);
                    stack.Push(newItem);
                    yield return newItem;
                }
            }
        } 
    }
    

    The method takes two things: an item, and a relation that produces the set of everything that is adjacent to the item. It produces a depth-first traversal of the transitive and reflexive closure of the adjacency relation on the item. Let the number of items in the graph be n, and the maximum depth be 1 <= d <= n, assuming the branching factor is not bounded. This algorithm uses an explicit stack rather than recursion because (1) recursion in this case turns what should be an O(n) algorithm into O(nd), which is then something between O(n) and O(n^2), and (2) excessive recursion can blow the stack if the d is more than a few hundred nodes.

    Note that the peak memory usage of this algorithm is of course O(n + d) = O(n).

    So, for example:

    foreach(Node node in Traversal(myGraph.Root, n => n.Children))
      Console.WriteLine(node.Name);
    

    Make sense?

提交回复
热议问题