处理常见的递归函数

时间:2009-05-19 14:38:29

标签: c# recursion hierarchy

我注意到在我的项目中,我们经常编写递归函数。

我的问题是:有没有办法为每个使用递归迭代的层次结构创建递归函数作为泛型函数?

也许我可以使用获取递归的根和结束标志的委托?

有什么想法吗?

感谢。

5 个答案:

答案 0 :(得分:1)

我认为你想要的是一种以通用方式使用层次结构的方法(英语中定义的“通用”,不一定是.Net中定义的)。例如,当我需要在Windows窗体中获取所有控件时,这是我写过的内容:

public static IEnumerable<T> SelectManyRecursive<T>(this IEnumerable<T> items, Func<T, IEnumerable<T>> selector)
{
    if (items == null)
        throw new ArgumentNullException("items");
    if (selector == null)
        throw new ArgumentNullException("selector");

    return SelectManyRecursiveInternal(items, selector);
}

private static IEnumerable<T> SelectManyRecursiveInternal<T>(this IEnumerable<T> items, Func<T, IEnumerable<T>> selector)
{
    foreach (T item in items)
    {
        yield return item;
        IEnumerable<T> subitems = selector(item);

        if (subitems != null)
        {
            foreach (T subitem in subitems.SelectManyRecursive(selector))
                yield return subitem;
        }
    }
}


// sample use, get Text from some TextBoxes in the form
var strings = form.Controls
                  .SelectManyRecursive(c => c.Controls) // all controls
                  .OfType<TextBox>() // filter by type
                  .Where(c => c.Text.StartWith("P")) // filter by text
                  .Select(c => c.Text);

另一个示例:Category类,其中每个Category可以ChildCategoriesControl具有Controls集合的方式相同)并假设rootCategory 1}}直接或间接是所有类别的父级:

// get all categories that are enabled
var categories = from c in rootCategory.SelectManyRecursive(c => c.ChildCategories)
                 where c.Enabled
                 select c;

答案 1 :(得分:1)

  

我的问题是:有没有办法为每个使用重复迭代的层次结构创建递归函数作为泛型函数?   可能我可以使用获取递归的根和结束标志的委托吗?

是 - 您唯一需要的是一个委托函数,它可以计算每个元素的子代码列表。当没有孩子返回时,该函数终止。

    delegate IEnumerable<TNode> ChildSelector<TNode>(TNode Root);

    static IEnumerable<TNode> Traverse<TNode>(this TNode Root, ChildSelector<TNode> Children) {
        // Visit current node (PreOrder)
        yield return Root;

        // Visit children
        foreach (var Child in Children(Root)) 
            foreach (var el in Traverse(Child, Children))
                yield return el;

    }

示例:

        static void Main(string[] args) {

        var Init = // Some path

        var Data = Init.Traverse(Dir => Directory.GetDirectories(Dir, "*", SearchOption.TopDirectoryOnly));

        foreach (var Dir in Data)
            Console.WriteLine(Dir);

        Console.ReadKey();
    }

答案 2 :(得分:0)

我不确定你的问题究竟是什么,但递归函数可以是通用的。对此没有限制。例如:

int CountLinkedListNodes<T>(MyLinkedList<T> input) {
   if (input == null) return 0;
   return 1 + CountLinkedListNodes<T>(input.Next);
}

答案 3 :(得分:0)

更简单且通用的方法可能是缓存函数的结果并仅在结果已知时使用“实际”函数 - 此方法的有效性取决于递归期间使用同一组参数的频率

如果您了解Perl,您应该查看Higher-Order Perl的前4章,这些章节可以作为电子书使用,所提出的想法与语言无关。

答案 4 :(得分:0)

听起来您的解决方案可以成功使用Visitor Pattern

您可以通过创建Visitor Pattern来创建hierarchical visitor pattern的特定变体。

这里完全讨论有点复杂,但这应该让你开始进行一些研究。基本思想是你有一个知道如何遍历结构的类,然后你有访问类知道如何处理特定节点。您可以使用节点处理来分离树的遍历。