재귀 호출을 이해하기 위해서는 스택(Stack)이라는 자료 구조를 먼저 살펴보는 것이 좋다. 왜냐하면 컴퓨터는 호출 스택이라고 불리는 스택 사용하여 함수를 실행하기 때문이다.
자료를 넣는 것은 push라고 하며, 빼는 것은 pop이라고 한다.
스택은 자료의 입출력이 언제가 목록의 한 쪽 끝에서만 일어난다. 즉, 자료를 한 쪽 끝에서만 넣거나 뺄 수 있는 선형 구조이며 가장 나중에 들어간 자료가 가장 먼저 나온다. 이것을 LIFO(Last In First Out)라고 부르기도 한다.
function factorial (n) {
if (n === 1) { // Base case, Termination case
return 1;
}
return n * factorial(n - 1);
}
factorial(3); // 6
3 * factorial(3 - 1);
이 되고 factorial(3 - 1)
은 factorial(2)
로 변환되어 실행한다.3 * factorial(2 - 1)
은 factorial(1)
로 변환되어 실행한다.3 * factorial(3 - 1); 3 * 2 = 6
↓ ↑
2 * factorial(2 - 1); 2 * 1 = 2
↓ ↑
1 return 1 return
function factorial (n) {
return n * factorial(n - 1);
}
위의 코드를 실제로 실행하게 되면 Maximum call stack size exceeded. 최대 호출 스택 사이즈가 초과되었다. 이 부분이 바로 우리가 재귀 함수를 사용할 때 가장 유의해야하는 부분이다.
재귀 함수를 작성하여 호출하면 함수는 자기 자신을 계속해서 호출하여 실행한다. 이 때 특정 조건이 되었을 때, 재귀 호출을 종료하는 문장이 반드시 하나 이상 존재 해야 하는데, 이렇게 재귀 호출을 중단시키는 조건 문장을 Base case 또는 Termination case라고 한다.
위의 팩토리얼 코드는 Base case가 없으므로 factorial(4)
, factorial(3)
, ..., factorial(-1)
, factorial(-2)
... 이렇게 음수의 영역까지 계속해서 호출하며 순차적으로 스택에 쌓을 것이고 어느 순간 정해진 메모리 용량을 초과하여 위와 같은 에러 메시지를 출력하게 된다.