스택 오버 플로우를 피하는 방법에 대한 재귀를 사용할 때 일반적인 규칙이 있습니까?C에서 재귀 사용 #
답변
당신에 따라 달라집니다 재귀 할 수있을 것입니다 얼마나 많은 시간 :
- 스택의 크기 (보통 1메가바이트 IIRC,하지만 이진 손으로 편집 할 수 있습니다, 나는 이렇게 권하고 싶지 않다) 재귀 사용의 각 단계 사용중인
- JIT를 사용 (10 개 캡처되지
Guid
지역 변수와 방법은 예를 들어, 로컬 변수가없는 방법보다 더 많은 스택을 가지고있을 것입니다) 얼마나 많은 스택 - - 때때로 JIT 은을 사용합니다. 꼬리 재귀를 사용합니다. . 규칙은 복잡하고 기억이 안납니다. (거기에 blog post by David Broman back from 2007 및 an MSDN page from the same author/date,하지만 그들은 지금 날짜가있을 수 있습니다.)
어떻게 스택 오버 플로우를 방지하기 위해? 너무 멀리 재발하지 마라 :) 재귀가 매우 멀리 가지 않고 종료 될 것이라고 합리적으로 확신 할 수 없다면 (매우 안전하지만 "10 이상"에 대해 걱정할 것입니다) 재귀를 피하기 위해 재 작성하십시오.
TCO는 64 비트 IIRC에서만 발생한다고 생각합니다. 다른 모든 경우에는 여전히 전화에 꼬리를 붙일 필요가 있습니다. 그리고 규칙을 지키지 않으면 꼬리가 아닐 수도 있습니다. – leppie
@leppie : 내가 기억하지 못했던 정확한 종류의 규칙 :) 블로그 게시물을 파헤쳐 볼 수 있는지 알게 될 것입니다. –
@ 존 여기 내가 찾은 하나 : http://blogs.msdn.com/davbr/pages/tail-call-jit-conditions.aspx –
합리적인 스택 크기를 유지하고 실제로 문제가 아닌 작은 문제를 계속 해결할 수 있도록 문제를 나누고 정복하는 것 외에도.
나는 하드 세트을 인식하지 못하므로 스택 오버 플로우가 발생하지 않습니다. 나는 개인적으로 보장하려고 노력한다. -
1. 나는 나의 근거가 옳다.
2. 코드가 어느 시점에서 기본 사례에 도달합니다.
많은 스택 프레임을 생성하는 경우 재귀를 루프로 풀어야 할 수 있습니다.
특히 여러 레벨의 재귀 (A-> B-> C-> A-> B ...)를 수행하는 경우 해당 레벨 중 하나를 루프로 추출하여 메모리를 절약 할 수 있습니다 .
+1, 좋은 답변입니다. 루프에서 트리 파싱을 한 것을 보았습니다. 훨씬 빠르고 스택 안전했습니다. –
정상적인 제한은 연속 호출간에 스택에 많이 남아 있지 않으면 약 15000-25000 레벨입니다. IIS 6 이상인 경우 25 %
대부분의 재귀 적 알고리즘은 반복해서 표현할 수 있습니다.
할당 된 스택 공간을 늘리는 방법은 다양하지만 먼저 반복 버전을 먼저 찾아 보겠습니다. :)
정말로 재귀 알고리즘을 사용하고 있는지에 따라 다릅니다. 그것은 간단한 재귀가 있다면, 당신은 같은 것을 할 수 있습니다
public int CalculateSomethingRecursively(int someNumber)
{
return doSomethingRecursively(someNumber, 0);
}
private int doSomethingRecursively(int someNumber, int level)
{
if (level >= MAX_LEVEL || !shouldKeepCalculating(someNumber))
return someNumber;
return doSomethingRecursively(someNumber, level + 1);
}
그것은 재귀의 수준은 논리적 인 한계로 정의 될 수있는이 방법은 정말에만 유용하다는 것을 주목할 필요가있다. 이 문제가 발생할 수없는 경우 (예 : 나누기 및 정복 알고리즘) 단순성 대 리소스 제한의 균형을 어떻게 조정할지 결정해야합니다. 이런 경우 미리 정의 된 한도에 도달하면 메소드간에 전환해야 할 수 있습니다. quicksort 알고리즘에서 사용한이 작업을 수행하는 효과적인 방법은 목록의 전체 크기 비율로 수행하는 것입니다. 이 경우 논리 한계는 조건이 더 이상 최적이 아닌 경우의 결과입니다.
+1 - 동일한 말을하려고했습니다 –
이 솔루션이 마음에 들지만 시스템에 종속적이지 않습니까? 일부 시스템은 더 많은 레벨을 처리 할 수 있으며 런타임에이를 판별 할 수있는 방법이 없습니다. 또한, 많은 스택 프레임이 필요하다면, 이걸 가지고 프로그램을 무력하게 만들 수 있습니다. – DevinB
맞아,하지만 한계는 논리적이어야한다. (알고리즘에 기반하여) 기계적 능력에 기초한 물리적 인 것이 아니어야한다. 그렇지 않으면, 당신이 평행을 이룬다면 당신은 벽에 부딪 칠 것입니다. –
나는 단지 꼬리 - 재귀를 생각했지만, C#은 그것을 지원하지 않는다는 것이 밝혀졌습니다. 그러나 닷넷 프레임 워크를 지원하는 것 : 당신이 그때는 아마 끔찍하게 잘못 뭔가를하고 있으며, 시스템 제한에 대해 문의해야하는 경우
http://blogs.msdn.com/abhinaba/archive/2007/07/27/tail-recursion-on-net.aspx
제작 된 일리노이가 중요한 모든 것이 아니라는 점에 유의하십시오. JIT *는 일리노이 코드에서 꼬리 호출 최적화를 수행합니다 (Jon의 답변 참조). –
는, 기억하십시오.
따라서 일반적인 작업에서 스택 오버플로가 발생할 것으로 생각되면 문제에 대한 다른 접근 방법을 생각해 내야합니다.
반복적 인 함수를 반복적 인 함수로 변환하는 것은 어렵지 않습니다. 특히 C#에는 Generic :: Stack 컬렉션이 있습니다. 스택 유형을 사용하면 스택 대신 프로그램의 힙에 사용 된 메모리가 이동합니다. 이렇게하면 재귀 데이터를 저장할 전체 주소 범위가 제공됩니다. 그만큼 충분하지 않다면 디스크에 데이터를 페이지하기가 어렵지 않습니다. 하지만이 단계에 이르면 다른 해결책을 진지하게 고려할 것입니다.
시스템 제한에 대해 묻지 않고 일부 지식을 얻으려고합니다 .... –
기본 CLR에서 실행중인 경우 스레드의 기본 스택 크기는 1MB입니다. 그러나 다른 호스트가이를 변경할 수 있습니다. 예를 들어 ASP 호스트는 기본값을 256KB로 변경합니다. 즉, VS에서 완벽하게 작동하지만 실제 호스팅 환경에 배포 할 때 코드가 손상 될 수 있습니다.
다행히 올바른 생성자를 사용하여 새 스레드를 만들 때 스택 크기를 지정할 수 있습니다. 제 경험상 거의 필요하지 않지만 이것이 해결책이었던 한 사례를 보았습니다.
바이너리 자체의 PE 헤더를 편집하여 기본 크기를 변경할 수 있습니다. 주 스레드의 크기를 변경하려는 경우 유용합니다. 그렇지 않으면 스레드를 만들 때 적절한 생성자를 사용하는 것이 좋습니다.
나는 here에 대해 짧은 글을 썼다. 기본적으로 depth라는 선택적 매개 변수를 전달합니다. 깊이가 갈 때마다 1을 더합니다. 재귀 적 방법 내에서 값의 깊이를 확인합니다. 설정 한 값보다 큰 경우 예외가 발생합니다. 값 (임계 값)은 응용 프로그램 요구 사항에 따라 다릅니다.
- 1. C에서 재귀 기능 ++
- 2. 재귀 (사용 PHP)
- 3. C에서 재귀 및 스택이없는 트래버스 트리
- 4. C에서 무료() 사용
- 5. C에서 루프의 strtok() 사용?
- 6. C에서 argv 사용?
- 7. Objective C에서 '^'기호 사용
- 8. C에서 단축키 사용 #
- 9. C에서 nullable 형식 사용
- 10. Objective C에서 extern 사용
- 11. C에서 프린터 사용
- 12. Objective C에서 CString 사용
- 13. C에서 SHA1 사용
- 14. 하스켈에서 기호 단순화 (재귀 사용?)
- 15. Unity IOC 재귀 - 요격기 사용?
- 16. pre_order C에서 스택 사용 traversal
- 17. SWIG에서 C에서 Ruby 블록 사용
- 18. C에서 트리 노드 클래스 사용 #
- 19. C에서 가상 함수의 실제 사용 #
- 20. C에서 자동 완성 기능 사용
- 21. Objective-C에서 enum을 사용 하시겠습니까?
- 22. 객관적인 C에서 중첩 참조 사용
- 23. C에서 mount (2) 함수 사용
- 24. C에서 폴더 경로에/또는 \\ 사용
- 25. C에서 sendInput을 사용하여 마우스 사용
- 26. Objective-C에서 프로토콜 버퍼 사용
- 27. 프로그래밍 방식으로 C에서 CMD 사용
- 28. C에서 두 번 사용 가능합니까?
- 29. C에서 비트 세트 컨테이너를 사용 ++
- 30. objective-c에서 C++ 클래스 사용
프로그래밍에 하드 세트 규칙이 있습니까? – Jason
공정한 포인트 - "하드 세트"에서 "일반"으로 질문을 변경했습니다. –
Not C#-specific. 모든 규칙이 모든 언어에 적용됩니다. –