简体   繁体   English

如何进行递归搜索?

[英]How to perform a recursive search?

I have a Task class which can have sub tasks of the same type 我有一个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)
  {}
}

How should i perform a recursive search (linq perhaps) to find the task with the earliest start date? 我应该如何执行递归搜索(也许linq)以找到具有最早开始日期的任务?

My initial approach involved too many for loops and it ended becoming a bit of a mess and quickly spiraling out of control. 我最初的方法涉及太多的循环,它结束了变得有点乱,并迅速失控。 Here's my second attempt: 这是我的第二次尝试:

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;
}

Any nicer solutions out there to solve this problem? 有什么更好的解决方案可以解决这个问题吗?

Thanks 谢谢

Svick's solution is fine, but I thought I'd add a bit more general advice. Svick的解决方案很好,但我想我会添加一些更一般的建议。 It seems like you are new to writing recursive methods and were struggling a bit there. 看起来你是编写递归方法的新手并且在那里苦苦挣扎。 The easiest way to write a recursive method is to strictly follow a pattern: 编写递归方法的最简单方法是严格遵循以下模式:

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;
}

So suppose you want to solve the problem "what is the maximum depth of my binary tree?" 所以假设你想解决问题“我的二叉树的最大深度是多少?”

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;
}

You need three things to make recursion work: 你需要三件事来做递归工作:

  • The problem has to get smaller every time you recurse. 每次递归时问题都必须变
  • The problem has to eventually get so small that it can be solved without recursion 问题必须最终变得如此之小,以至于无需递归就可以解决问题
  • The problem has to be solvable by breaking it down into a series of smaller problems, solving each one, and combining the results. 问题必须通过将其分解为一系列较小的问题,解决每个问题并将结果组合来解决。

If you cannot guarantee those three things then do not use a recursive solution . 如果你不能保证这三件事,那么就不要使用递归解决方案

You're right, recursion is the right approach here. 你是对的,递归是正确的方法。 Something like this should work: 这样的事情应该有效:

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;
}

I removed the check for task.HasSubTasks() , because it only makes the code more complicated without any added benefit. 我删除了task.HasSubTasks()的检查,因为它只会使代码更复杂而没有任何额外的好处。

If you find your often write code that needs to walk all of the tasks in the tree, you might want to make this more general. 如果您发现经常编写代码需要遍历树中的所有任务,您可能希望使其更加通用。 For example, you could have a method that returns IEnumerable<Task> that returns all the tasks in the tree. 例如,您可以使用返回IEnumerable<Task>的方法,该方法返回树中的所有任务。 Finding the smallest start date would then be as easy as: 找到最小的开始日期将非常简单:

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

Separating iteration over tree from search may be beneficial if there are other tasks you want to do on all items. 如果您要对所有项目执行其他任务,则从搜索中分离树的迭代可能是有益的。 Ie if you implement IEnumerable over the tree items you can use LINQ queries to search for anything you want or perform other operations on all tasks in you tree. 即如果您在树项上实现IEnumerable,您可以使用LINQ查询来搜索您想要的任何内容,或者对您树中的所有任务执行其他操作。 Check out Implementing IEnumerable on a tree structure for a way to do so. 检查在树结构上实现IEnumerable以获取实现方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM