遍历对象的所有后代

时间:2014-08-14 08:56:42

标签: c# algorithm recursion graph-algorithm traversal

我在遍历对象的所有后代时遇到问题。

以下代码中的'unit'在我的程序中属于Unit类型。它有一个属性ChildUnits,它返回单元子级的List<Unit>

我可以成功地对孩子们进行操作。然后我检查这些孩子是否有孩子,如果他们这样做,我也可以对他们进行操作。

但是,我需要检查所有后代,以防有更多的深度而不仅仅是孙子。除了下面的代码之外,我还使用了while循环,但是它非常混乱所以我把它留了出来。

这是我恢复的代码:

foreach (var child in unit.ChildUnits)
{
    //do something here with the child (I know it sounds dodgy).

    bool hasMoreChildren = child.ChildUnits.Count != 0;

    if(hasMoreChildren)
    {
        foreach (var descendant in child.ChildUnits)
        {
            //do something here with the descendant.
        }
    }
}

我可以深入到另一个层次,因为一个单位的深度比这个更深。但那不是一个干净的解决方案。

我想我可能需要使用图遍历算法和/或递归,但我想就如何最有效地解决这个问题提出一些建议。

编辑:是否可以在不定义新功能/方法的情况下执行此操作?

4 个答案:

答案 0 :(得分:1)

这样的算法:

def traverse(Unit i):
       for (Unit child : i.childList):
                  // Perform your logic for child
                  traverse(child)

这将为第一个节点的每个子节点执行相同的功能,并且当将其应用于i.child [j]时,它将为所有i.child [j] .child [k]执行相同的功能,因此它将为每个节点及其所有子节点执行所需的操作。

而你可以使用stack:

stack s; 
s.push(firstNode);
while(!stack.empty()):
    t = stack.pop()
    foreach(Unit child : t):
        s.push(child)
        // Perform logic for child

答案 1 :(得分:1)

您可以使用递归:

void processChildren(List<Unit> children)
{
    foreach (var child in children)
    {
        //do something here with the child (I know it sounds dodgy).
        processChildren(child.Children); // recursive call here
    }
}

如果您不想定义新方法,您也可以自己堆叠:

var stack = new Stack<Unit>();
stack.push(firstUnit);
while( !stack.Any() ) {
    var item = stack.pop();
    //do something here with the item

    foreach(var child in item.Children)
    {
        stack.push(child);
    }
}

答案 2 :(得分:1)

  

编辑:是否可以在不定义新功能/方法的情况下执行此操作?

您可以使用匿名方法...这不完全是“未定义新方法”,我知道:)

但是,还有另一个问题需要注意:循环引用...... even if you dont think there will be any

这是一个实现,没有定义任何新方法

Action<IEnumerable<Unit>> process = null;
var processed = new HashSet<Unit>();
process = list => {
   foreach(var u in list.Where (processed.Add))
    {
        // do something here with u
        //... and then process children
        process(u.ChildUnits);
    }
};

process(myList); // do the actual processing

答案 3 :(得分:0)

在没有递归或action / lambda的情况下执行此操作的另一种方法是使用包含要处理的项的列表。

喜欢这个。

var toDoList = new List<Unit> { unit };
while (toDoList.Any()) {
    // Get current child, and remove it from the to-do-list
    var currentChild = toDoList.First();
    toDoList.RemoveAt(0);

    // Do something with the current child.
    // ...

    // Now see, if the child has any children to handle
    if (currentChild.ChildUnits != null && currentChild.ChildUnits.Any()) {
        toDoList.AddRange(currentChild.ChildUnits);
    }
}