有一种简单的方法来计算递归数据结构中的元素吗?

时间:2013-08-16 13:25:07

标签: c#

我在C#对象中有一个递归数据结构。

对象具有“部件”的集合。每个零件还有一个零件集合。等等。这个结构理论上可以永远嵌套。

object
--> Part
--> Part
  --> Part
  --> Part
    --> Part
  --> Part
--> Part

我想得到这个结构中所有部件的数量。所以,所有的分支和叶子。 (在上面的例子中,共有7个部分。)

有没有办法在不初始化计数器并在树中递归的情况下执行此操作?当然,我可以做到这一点,但它看起来很慢而且有点过分。有更好/更简单的方法吗?

4 个答案:

答案 0 :(得分:5)

处理递归数据结构的一种自然方式是计数或任何其他类型的聚合,它采用递归函数:

class Part {
    IEnumerable<Part> SubParts {get;set;}
    public int TotalParts {
        get {
            return 1 + SubParts.Sum(p => p.TotalParts);
            //     ^                       ^
            //     |                       |
            // Add one for this part       |
            //                             |
            //         Use LINQ to aggregate counts recursively
        }
    }
}

该函数假设较低级别的部分不在较高级别的部分之间共享,即部分图形是树。提高这类函数性能的一种方法是将结果缓存在Part以下的级别,以确保递归计算只进行一次。

您可以通过实现队列或堆栈来避免递归,但实现不会那么简单。

答案 1 :(得分:2)

您可以覆盖每个元素上的Add方法,并在添加元素时在每个Part上保留count属性,类似于List.Count

否则,没有比迭代更准确的方法了。对于大小的估计,您可以采用代表性样本并从中推断出粗略的大小。

答案 2 :(得分:2)

这是一个非递归解决方案,而不是迭代解决方案,它也能够遍历树并计算节点。

public class Part
{
    public IEnumerable<Part> Children { get; set; }
    public int Count()
    {
        var stack = new Stack<Part>();
        stack.Push(this);

        int total = 0;
        while (stack.Any())
        {
            total++;
            foreach (var child in stack.Pop().Children)
                stack.Push(child);
        }

        return total;
    }
}

答案 3 :(得分:0)

我只是使用递归,但是如果你真的想要避免它,那么你可以覆盖集合的Add / Remove方法,并使用委托给包含对象的方法,该对象更新{{1的单个实例变量(每个包含对象,而不是每个集合)。每次在树中的任何集合中添加或删除部件时,都会通过委托修改totalCount变量。

每个集合节点都不知道它的父/子节点的数量,并且集合本身隐藏了总计数如何维护的实现。