2012-02-29 2 views
10

캔버스에 일부 원을 이동시키는 재귀 함수가 있습니다. Overed 원이 확대되고 (확대) 다른 모든 원이 밀려납니다. 푸시 된 원은 확대가 완료 될 때까지 다른 원을 밀어냅니다.자바 스크립트 재귀 : 최대 호출 스택 크기가 초과되었습니다.

"최대 호출 스택 크기를 초과했습니다"라는 오류 메시지가 나타나지만 문제를 이해하지만 해결 방법을 모르겠습니다 ... 일반적으로 재귀 문제를 해결할 수있는 세 가지 해결책이 있습니다 :

  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

    반복적 인 솔루션을 만들기 위해 필요한 숫자 또는 작업을 알 필요가 없습니다. 요점은 자바 스크립트 스택을 자신의 스택으로 대체하는 것입니다. 그것을 구현하는 방법을 예를 보려면이 답변을 확인 : 그것은 push()pop() 지원하기 때문에 Link

    당신은 자바 스크립트의 스택으로 Array 객체를 사용할 수 있습니다.

    추 신 : Jim의 대답이 제안했듯이 일반적으로 이러한 재귀 수준이 필요하지 않은 알고리즘을 찾을 수 있습니다.

    +2

    답변도 도움이되었지만 슬프게도 단 하나의 답변 만 수락 할 수 있습니다. 감사합니다. – fizis

    +1

    나는이 감정을 전달하기 위해 당신을 위해 그것을 upvoted했습니다. – agm1984

    관련 문제