지금까지 재귀적으로 작성하는 법과 재귀로 보다 복잡한 문제를 해결하는 법을 배웠지만 재귀로 확실히 어떤 문제는 해결할 수 있어도 제대로 사용하지 않으면 또 다른 문제가 발생한다.
재귀는 종종 O(2ⁿ)같은 가장 느린 빅 오 카테고리의 주된 요인이 된다.
다음의 재귀 함수는 배열의 최대값을 찾는다.
function max(array) {
if (array.length === 1) return array[0];
if (array[0] > max(array.slice(1))) {
return array[0];
} else {
return max(array.slice(1));
}
}
만약 배열의 요소가 하나면 그 값이 최대값이 된다.
각 재귀 호출의 핵심은 하나의 수 (array[0])와 나머지 배열의 최대값 간의 비교다.
if-else 조건을 보면, 조건문 앞 뒤로 max() 함수가 두 번 나온다. 이는 비효율적이다.
[1, 2, 3, 4]
를 예시로 들면, 1
과 [2, 3, 4]
의 최댓값을 비교한다. 이어서 2
와 [3, 4]
의 최댓값을 비교한다. 이어서 3
과 [4]
를 비교하고, [4]
의 최댓값을 찾는 것이 기저 조건이다.
코드가 어떻게 실행되는지 제대로 알려면 바닥 호출부터 분석해 호출 사슬을 따라 올라가야 한다.
max([4])를 호출하면 함수는 단순히 숫자 4를 반환한다. 배열에 원소가 하나일 때가 기저 조건이기 때문이다.
호출 사슬 위로 올라가서 max([3, 4])
를 호출하면, 배열의 요소가 1개가 아니므로 3
과 max([4])
를 비교하면서 max([4])
를 호출한다.
3
은 4
보다 크지 않으므로 else
문인 max(array.slice(1))
을 실행하고, max([4])
가 반환되며 두 번째로 호출된다.
즉, max([3, 4])
는 max([4])
를 두 번 호출한다.
max([2, 3, 4])
는 2
와 max([3, 4])
를 호출하고, max([3, 4])
는 앞서 봤던 것처럼 max([4])
를 두 번 호출한다. 그리고 else
문에 따라 max([3, 4])
를 호출하고, max([4])
는 추가로 두 번 더 호출된다.
max([1, 2, 3, 4])
를 호출하면 실제로 max
함수를 총 15번 호출하게 된다. 이때 모든 15번의 호출이 필요한 것은 아니다. max([4])
는 한 번만 호출되면 충분한데도 8번이나 호출되고 있다.
추가적인 재귀 호출을 전부 없애기 위해서, 코드에서 max
를 딱 한 번만 호출하고 그 결과를 변수에 저장하는 방법을 쓴다.