如何进行递归搜索?

时间:2012-02-16 02:02:24

标签: c# linq design-patterns recursion tree

我有一个Task类,它可以有相同类型的子任务

public class Task
{
  public DateTime Start { get; set;}
  public DateTime Finish { get; set;}
  public List<Task> Tasks {get; set;}
  public DateTime FindTaskStartDate(Task task)
  {}
}

我应该如何执行递归搜索(也许是linq)以找到具有最早开始日期的任务?

我最初的方法涉及太多的循环,它结束了变得有点乱,并迅速失控。这是我的第二次尝试:

public DateTime FindTaskStartDate(Task task)
{
    DateTime startDate = task.Start;

    if(task.HasSubTasks())
    {
        foreach (var t in task.Tasks)
        {
            if (t.Start < startDate)
            {
                startDate = t.Start;

                if (t.HasSubTasks())
                {
                    //What next?
                    //FindTaskStartDate(t);
                }
            }
        }
    }

    return startDate;
}

有什么更好的解决方案来解决这个问题?

由于

3 个答案:

答案 0 :(得分:14)

Svick的解决方案很好,但我想我会添加一些更一般的建议。看起来你是编写递归方法的新手并且在那里苦苦挣扎。编写递归方法的最简单方法是严格遵循模式:

Result M(Problem prob)
{
    if (<problem can be solved easily>)
        return <easy solution>;
    // The problem cannot be solved easily.
    Problem smaller1 = <reduce problem to smaller problem>
    Result result1 = M(smaller1);
    Problem smaller2 = <reduce problem to smaller problem>
    Result result2 = M(smaller2);
    ...
    Result finalResult = <combine all results of smaller problem to solve large problem>
    return finalResult;
}

所以假设你想解决问题“我的二叉树的最大深度是多少?”

int Depth(Tree tree)
{
    // Start with the trivial case. Is the tree empty?
    if (tree.IsEmpty) return 0;
    // The tree is not empty. 
    // Reduce the problem to two smaller problems and solve them:
    int depthLeft = Depth(tree.Left);
    int depthRight = Depth(tree.Right);
    // Now combine the two solutions to solve the larger problem.
    return Math.Max(depthLeft, depthRight) + 1;
}

递归工作需要三件事:

  • 每次递归时,问题都必须更小
  • 问题必须最终变得如此之小以至于无需递归就可以解决
  • 问题必须通过将其分解为一系列较小的问题,解决每一个问题并将结果组合来解决。

如果你不能保证这三件事,那么就不会使用递归解决方案

答案 1 :(得分:6)

你是对的,递归是正确的方法。这样的事情应该有效:

public DateTime FindTaskStartDate(Task task)
{
    DateTime startDate = task.Start;

    foreach (var t in task.Tasks)
    {
        var subTaskDate = FindTaskStartDate(t);
        if (subTaskDate < startDate)
            startDate = subTaskDate;
    }

    return startDate;
}

我删除了对task.HasSubTasks()的检查,因为它只会使代码更复杂而没有任何额外的好处。

如果您发现经常编写的代码需要遍历树中的所有任务,您可能希望使其更加通用。例如,您可以使用返回IEnumerable<Task>的方法来返回树中的所有任务。找到最小的开始日期将非常简单:

IterateSubTasks(task).Min(t => t.Start)

答案 2 :(得分:0)

如果要对所有项目执行其他任务,则从搜索中分离树的迭代可能会有所帮助。即如果在树项上实现IEnumerable,则可以使用LINQ查询来搜索所需的任何内容,或者对树中的所有任务执行其他操作。 查看Implementing IEnumerable on a tree structure了解相关方法。