【发布时间】:2017-11-11 14:06:03
【问题描述】:
我正在编写遍历以找到道路中最长的路径。这段代码的神奇部分是段。Next 指的是应用了特定逻辑的 LINQ,例如不重新访问已访问的节点。因此,旅行中的瑕疵不要指出超出范围。
我正在尝试做的是减少堆栈上的调用次数,因为有时路径可能长达 5000 次。我知道我必须使这个递归调用尾递归。
public static IEnumerable<Segment> FindLongestPath(Segment segment)
{
var rv = new List<Segment> {segment};
var longestPathLength = 0;
var longestNextPaths = Enumerable.Empty<Segment>();
foreach (var n in segment.Next)
{
var paths = FindLongestPath(n);
var length = paths.Sum(p => p.LengthMeters);
if (length > longestPathLength)
{
longestPathLength = length;
longestNextPaths = paths;
}
}
rv.AddRange(longestNextPaths);
return rv;
}
如何使这个递归调用成为尾递归?我知道我可能必须在旅行时维护IEnumerable<Segment>,但我只是没有把头缠在它身上。
【问题讨论】:
-
我认为您需要在 var paths = FindLongestPath(n) 调用之后,将 n 添加到“已检查所有子路由”ienumberable 中,您将在之前检查 n 是否存在FindLongestPath 并继续循环(如果是)。当然,这也必须传递到 findlongestpath 中
-
我注意到,您的方法不仅可能会破坏堆栈,而且如果没有,它产生的冗余列表的数量是巨大的。您最好在这里制作路径不可变堆栈,然后您可以将新元素推送到其中而无需重新分配和复制主体。