2012-02-29 80 views
10

我有一个递归函数来移动画布上的一些圆圈。内圈被放大(放大),所有其他圈被推开。 推动的圆圈推动其他圆圈等,直到缩放完成。JavaScript递归:超出最大调用堆栈大小

我得到一个错误“最大调用堆栈大小超过了”,我理解这个问题,但我只是不知道如何解决它... 我发现了三个可能的解决方案用于解决一般的递归问题:

  1. 更改递归进行迭代
  2. 使用memoization
  3. 使用的setTimeout

但我认为,我可以使用他们没有:

  1. 我无法实现,因为操作的未知数量需要反复
  2. 我不明白,记忆化不够好,但我认为它不适合或者(或也许我错了,有人可以告诉我)
  3. 我不能使用SetTimeout,因为它应该阻止在这个特定动画的函数调用。

如何解决此问题?

// Pushes circles aside when some other circle leans on these circles (on zoom in) 
var moveCirclesAside = function(circle1, circleToSkip, groupOfMoves) { 
    var count = circles.length; 
    for (var i = 0; i < count; i++) { 

     // Skip the same circle 
     if (i == circle1.i) { 
      continue; 
     } 

     // Also skip the circle which was intended not to move any further 
     if (circleToSkip != null && i == circleToSkip.i) { 
      continue; 
     } 

     // Get second circle 
     var circle2 = circles[i]; 

     // Calculate a distance between two circles 
     var dx = circle2.x - circle1.x; 
     var dy = circle2.y - circle1.y; 
     var distance = Math.sqrt((dx * dx) + (dy * dy)); 

     // If circles already collided need to do some moving... 
     if (distance <= circle1.r + circle2.r + OD.config.circleSpacing) { 

      // Get collision angles 
      var angle = Math.atan2(dy, dx); 
      var sine = Math.sin(angle); 
      var cosine = Math.cos(angle); 

      // Some circle position calculation 
      var x = OD.config.circleSpacing; 
      var xb = x + (circle1.r + circle2.r); 
      var yb = dy * cosine - dx * sine; 

      // Save each state (move) of any circle to the stack for later rollback of the movement 
      groupOfMoves.push(copyCircleByVal(circle2)); 

      // Move the circle 
      circle2.x = circle1.x + (xb * cosine - yb * sine); 
      circle2.y = circle1.y + (yb * cosine + xb * sine); 

      // Make sure that circle won't go anywhere out of the canvas 
      adjustCircleByBoundary(circle2); 

      // If moved circle leans against some other circles make sure that they are moved accordingly 
      // And such related moves must be grouped for correct rolback of moves later - so we pass 'groupOfMoves' var 
      moveCirclesAside(circle2, circle1, groupOfMoves); 
     } 
    } 
}; 

回答

5

这并不让人感到意外,因为算法迭代时堆栈增长,但退出条件不可预知,操作没有严格定位(它们对邻近圆圈有连锁效应),所以处理时间会变得混乱。

我会重新考虑算法。考虑找到两个最接近的圆,如果这些圆比分开的给定阈值更远,则中止。否则,将它们分开并重复一次。

7

1)我无法实现,因为所需要操作的未知数量的迭代;

嗯,我没有看过你的代码,但线性递归的一般避免(你在这里有一个线性的)看起来是这样的:

while (1 == 1) { 
    if (breakcondition) 
     break; 
    doSomeCode() 
} 

所以你不必知道确切的迭代次数,如for - 循环的情况。

3

您不需要知道您制作迭代解决方案所需的数量或操作。重点是用你自己的一个替换JavaScript栈。查看此答案以查看如何实现它的示例:Link

您可以在JavaScript中使用Array对象作为堆栈,因为它支持push()pop()。 PS:按照Jim的回答,你通常可以找到一个算法,它不需要这么多的递归级别。

+2

您的回答也很有帮助,但可悲的是我只能接受一个答案......谢谢! – fizis 2012-02-29 13:35:32

+1

我已经为你表达了这种感悟。 – agm1984 2017-11-12 21:07:11

相关问题