재귀를 활용한 최솟값 찾기
이 글에서는 숫자로 이루어진 배열을 입력받아 재귀(recursion)를 사용해 그중 가장 작은 수를 반환하는 JavaScript 함수를 만들어 보겠습니다.
재귀란 함수가 자기 자신을 다시 호출하는 프로그래밍 기법으로, 반복문을 사용하지 않고도 배열을 하나씩 줄여가며 문제를 해결할 수 있습니다.
예제 배열
다음과 같은 두 개의 배열이 있다고 가정해 보겠습니다.
const arr1 = [-2, -3, -4, -5, -6, -7, -8]; const arr2 = [-2, 5, 3, 0];
첫 번째 배열의 최솟값은 -8, 두 번째 배열의 최솟값은 -2가 되어야 합니다.
구현 코드
재귀를 이용해 최솟값을 찾는 코드는 다음과 같습니다.
const arr1 = [-2, -3, -4, -5, -6, -7, -8];
const arr2 = [-2, 5, 3, 0];
const min = arr => {
const helper = (a, ...res) => {
// 남은 요소가 없으면 현재 값이 곧 최솟값
if (!res.length) {
return a;
}
// 첫 번째 값이 나머지 요소보다 작으면 교체
if (a < res[0]) {
res[0] = a;
}
// 나머지 요소로 재귀 호출
return helper(...res);
};
return helper(...arr);
};
console.log(min(arr1));
console.log(min(arr2));코드 동작 원리
이 코드의 핵심은 내부에 정의된 helper 함수입니다. 동작 과정은 다음과 같습니다.
1. 매개변수 분리: 전개 연산자(spread operator)를 사용해 배열의 첫 번째 값은 a에, 나머지 값들은 res 배열에 담습니다.
2. 종료 조건 확인: res 배열이 비어 있으면 더 이상 비교할 값이 없다는 뜻이므로, 현재까지 유지된 최솟값 a를 그대로 반환하며 재귀를 종료합니다.
3. 값 비교 및 갱신: a가 res[0]보다 작다면 res[0]을 a로 교체하여 최솟값 후보를 갱신합니다.
4. 재귀 호출: 갱신된 배열을 다시 helper에 전달해 위 과정을 반복합니다. 호출될 때마다 배열의 크기가 하나씩 줄어들기 때문에 언젠가 종료 조건에 도달하게 됩니다.
실행 결과
콘솔에 출력되는 결과는 다음과 같습니다.
-8 -2
두 배열 모두 음수를 포함하고 있음에도 불구하고 정확한 최솟값이 출력되는 것을 확인할 수 있습니다.
마무리
이처럼 재귀를 활용하면 Math.min()이나 반복문 없이도 배열의 최솟값을 우아하게 구할 수 있습니다. 다만 배열의 길이가 매우 클 경우 재귀 호출 깊이 제한(스택 오버플로우)에 주의해야 하며, 실무에서는 Math.min(...arr) 또는 reduce() 메서드를 함께 참고하는 것이 좋습니다.