简体   繁体   中英

How to perform a recursive search?

I have a Task class which can have sub tasks of the same type

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?

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. 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.

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. 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. Check out Implementing IEnumerable on a tree structure for a way to do so.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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