在递归呼叫中跟踪父母

时间:2014-07-30 07:57:26

标签: c# recursion parent-child

我试图在递归调用中跟踪父母,并标记正确发生的父子关系。

有4个类(不介意名称,这是一个例子的虚拟代码):

  1. ChildBlock
  2. ChildFinally
  3. ChildDisposable
  4. 所有3个子类都从一个抽象类继承:Child。

    Root显然是拥有所有孩子的顶级人物,Root没有父母。但是,在某种程度上,其他类别也没有。 Root有孩子,每个孩子都有孩子;但反之亦然。 ChildBlock(以及所有其他人)没有存储父级,只有子级列表。见代码:

    internal abstract class Child
    {
        public string name;
        public List<Child> children;
    
        public Child()
        {
            name = "Child";
            children = new List<Child>();
        }       
    
        public virtual void AddChild(Child child)
        {
            children.Add(child);
        }
    }
    
    internal class ChildFinally : Child
    {
        public ChildFinally(string level)
        {
            name = level + ": ChildFinally";
            children = new List<Child>();
        }
    }
    

    假设你有一个孩子的Root(1级):ChildBlock(2级)。 ChildBlock,它自己有两个孩子:ChildFinally(3级)和ChildBlock(3级)。 ChildFinally(级别3)和ChildBlock(级别3)都有一个子级:ChildDisposable(级别4)。

    所以采用分层方式(我将它们着色以更准确地显示水平): enter image description here

    我想要实现的目标是:我想知道ChildDisposable(level 4)是否有父母,在他之上的任何级别,ChildFinally类型。

    这里的问题是,ChildDisposable并不知道它的父母,但是父母知道他的孩子(通过子女列表)。

    现在我在递归调用中循环遍历每个子项列表:

    private static void DisplayChildren(Child child)
    {
        foreach (Child c in child.children)
        {
            Console.WriteLine(c.name);
            DisplayChildren(c);
        }
    }
    

    这种递归调用必须保持这种状态。另外,我不能让孩子们知道他们的父母。

    有没有办法让我跟踪ChildDisposable类型的孩子是否有ChildFinally类型的父级(任何级别)?

    编辑:如果需要,我可以提供完整的(可重现的)虚拟代码。

3 个答案:

答案 0 :(得分:4)

根据我们所知道的情况很难判断,但我想我可以猜一下。

无论如何,如果我是对的,你会以某种方式你的树,所以我的建议是在你行走时记住某种路径信息/ em>你的树(应该是微不足道的 - 它只是你的 walker 的另一个参数) - 在那里你可以轻松存储像上一个 ChildFinally

这样的东西

那就是你的例子:

private static void DisplayChildren(Child child)
{
    DisplayChildren(child, new []{child});
}

private static void DisplayChildren(Child child, Child[] path)
{
    foreach (Child c in child.children)
    {
        Console.WriteLine(c.name);
        var newPath = new List<Child>(path);
        newPath.Add(c);
        DisplayChildren(c, newPath.ToArray());
    }
}

当然我不知道真正需要什么,所以这个例子只给你当前孩子的路径(包括它) - 应该很容易找到你需要的东西:

static bool HasFinalParent(Child[] path)
{
   return path.Any(c => c is ChildFinally);
}

或更容易(只记住父母,如果有的话):

private static void DisplayChildren(Child child)
{
    DisplayChildren(child, null);
}

private static void DisplayChildren(Child child, ChildFinally lastFinalParent)
{
    if (child is ChildFinally)
       lastFinalParent = (ChildFinally)child;

    foreach (Child c in child.children)
    {
        Console.WriteLine(c.name);
        DisplayChildren(c, lastFinalParent);
    }
}

答案 1 :(得分:1)

我在想字典

var parents = new Dictionary<Child, Child>();

void SetParent(Child parent)
{
    foreach (Child c in parent.children)
    {
       parents[c] = parent;
       SetParent(c);
    }
}

您只需使用SetParent(root)

调用一次

答案 2 :(得分:0)

这个怎么样:

internal abstract class Child
{
    public string name;
    public List<Child> children;

    public Child Parent {get;set;}

    public Child()
    {
        name = "Child";
        children = new List<Child>();
    }       

    public virtual void AddChild(Child child)
    {
        children.Add(child);
        child.Parent = this;
    }
}

public static class ChildHelpers
{
    public static Child[] GetAncestors(this Child self)
    {
        var path = new List<Child>();
        var current = self;
        while (current.Parent != null)
        {
            path.Add(current.Parent);
            current = current.Parent;
        }
        return path.ToArray(); // maybe reverse first...
    }
}

这会为每个孩子添加对父母的引用...

或者你必须通过一个&#34;父母定位服务&#34;在创建/作为孩子添加时,孩子可以通过自上而下遍历树直到找到孩子并在遍历期间记录祖先来确定父母。如果树很深并且你必须多次这样做,这可能是昂贵的......

如果结构在某种程度上是全局可访问和静态的(不是更可取!),您可以通过简单地调用静态&#34;父定位服务&#34;来完成。

如果您不想修改Child,您还可以为每个包装器构建包装器,包含父引用并将其传递给自己的孩子:

internal class ChildHolder
{
    public Child TheChild {get; private set;} // get the payload child
    public ChildHolder Parent {get;set;} // store information about parent

    public ChildHolder(Child child)
    {        
       TheChild = child;
    }

    public virtual void AddChild(ChildHolder childHolder)
    {
        TheChild.Add(childHolder.TheChild); // store children in original child object
        childHolder.Parent = this; // and pass my parent information to childs holder
    }

}