下面的C#代碼計算了一組點的最小封閉圓,但由於它的遞歸實現而導致堆棧溢出異常。將遞歸轉換爲循環
它是從哪個a paper指定的算法遞歸萃取。
該算法是而不是尾遞歸,它並不平凡可轉換爲循環結構。
的遞歸函數是
public static Circle MiniDiskImpl(IReadOnlyList<Point2D> points, List<Point2D> boundary)
{
if (!points.Any() || boundary.Count == 3)
{
if (boundary.Count == 0)
return null;
if (boundary.Count == 1)
return null;
if (boundary.Count == 2)
{
var radius = boundary[0].DistanceTo(boundary[1])/2;
var center = (boundary[0] + boundary[1])*0.5;
return new Circle(Plane.XY, center, radius);
}
return new Circle(Plane.XY,boundary[0],boundary[1],boundary[2]);
}
var p = points[0];
var Q = points.GetRange(1,points.Count - 1);
var D = MiniDiskImpl(Q, boundary);
if (D==null || D.Center.DistanceTo(p) >= D.Radius)
{
D = MiniDiskImpl(Q, boundary.Concat(p).ToList());
}
return D;
}
用戶調用此函數。
public static Circle MiniDisk(List<Point2D> points)
{
points = points.Slice(0); // Clone the list so we can manipulate in place
points.Shuffle(); // sorted points cause poor algorithm performance
return MiniDiskImpl(points, new List<Point2D>());
}
問題是,使算法不遞歸需要什麼轉換?
當然...重構(固定)代碼,以便'MiniDiskImpl'不會被調用兩次(你計算則覆蓋'D'現在),然後用標準的方法,將尾遞歸進入迭代。 – Sneftel
不應該到[codereview.se]? – hometoast
@Sneftel:第一次調用的結果在條件中使用,所以你不能這樣做。 –