재귀 함수(Recursive Function)는 자기 자신을 호출하는 함수입니다. 주어진 문제를 더 작은 동일한 문제로 나누어 해결하는 방식으로 동작하며, 주로 분할 정복(Divide and Conquer) 방식의 문제 해결에 사용됩니다.
재귀 함수는 기본적으로 두 가지 구성 요소를 가집니다:
1. 기저 사례(Base Case): 재귀 호출이 더 이상 이루어지지 않고 종료되는 조건입니다. 이를 통해 무한 루프를 방지합니다.
2. 재귀 호출(Recursive Case): 문제를 더 작은 문제로 분할하여 자기 자신을 호출하는 부분입니다.
재귀 함수는 문제를 더 작은 문제로 나누어 해결하는 방식으로 매우 유용하지만, 그 사용에는 장점과 단점이 존재합니다. 이를 잘 이해하고 적절히 활용하는 것이 중요합니다.
변수를 여럿 만들 필요가 없다
tmp와 같은 변수를 사용하기보다는 재귀 호출을 통해 자연스럽게 상태가 전달됩니다. 이를 통해 코드가 간결하고 직관적으로 작성될 수 있습니다.반복문 없이 간결한 코드 작성
메모리 사용 증가
컨텍스트 스위칭 비용
하노이의 탑은 고전적인 재귀 문제 중 하나로, 세 개의 기둥과 여러 개의 원판을 사용하여 한 기둥에서 다른 기둥으로 원판을 옮기는 문제입니다. 원판을 옮기는 규칙은 다음과 같습니다:
이 문제는 재귀로 해결할 수 있으며, 각 단계에서 문제를 더 작은 하위 문제로 나누어 해결합니다.
하노이의 탑을 풀기 위한 재귀 함수는 다음과 같은 절차를 따릅니다:
public class Hanoi {
public static void main(String[] args) {
int n = 3; // 원판 개수
moveTower(n, 'A', 'C', 'B'); // A -> C, B는 보조 기둥
}
// 하노이의 탑 함수
public static void moveTower(int n, char from, char to, char aux) {
if (n == 1) {
System.out.println("Move disk 1 from " + from + " to " + to);
} else {
// (1) n-1개의 원판을 보조 기둥으로 옮깁니다.
moveTower(n - 1, from, aux, to);
// (2) n번째 원판을 목표 기둥으로 옮깁니다.
System.out.println("Move disk " + n + " from " + from + " to " + to);
// (3) 보조 기둥에 있던 n-1개의 원판을 목표 기둥으로 옮깁니다.
moveTower(n - 1, aux, to, from);
}
}
}
moveTower(n, from, to, aux) 함수는 n개의 원판을 from 기둥에서 to 기둥으로 옮기는데, aux는 보조 기둥입니다.n == 1일 때는 원판을 바로 옮깁니다.n > 1일 때는 먼저 n-1개의 원판을 보조 기둥으로 옮기고, 가장 큰 원판을 목표 기둥으로 옮긴 후, 다시 보조 기둥에 있던 원판들을 목표 기둥으로 옮깁니다.n개의 원판을 이동하는 문제를 n-1개의 원판을 이동하는 문제로 나누는 방식으로 해결합니다.재귀 함수는 문제를 간결하고 직관적으로 해결할 수 있는 유용한 도구입니다. 하지만 과도한 재귀 호출은 메모리 사용과 성능 저하를 일으킬 수 있으므로, 재귀와 반복문을 적절히 선택하여 사용하는 것이 중요합니다. 문제의 특성에 맞는 방법을 선택하는 것이 성능을 최적화하는 데 도움이 됩니다.
추가 학습 자료