[자료구조] 재귀(Recursion)
2024. 11. 29. 13:49ㆍCS
재귀(Recursion)란?
함수가 자기 자신을 호출하여 문제를 해결하는 기법이다.
일반적으로 재귀 함수는 두 가지 구성 요소를 가진다.
- 기본 조건(Base Case): 재귀 호출을 종료시키는 조건
- 재귀 조건(Recursive Case): 함수가 자기 자신을 호출하는 조건
특징
- 문제를 작은 단위로 나누어 해결한다.
- 함수 호출 과정에서 스택 메모리를 사용한다.
- 무한 재귀 호출이 발생하면 스택 오버플로우(Stack Overflow)가 발생할 수 있다.
장단점
- 장점
- 코드가 간결하여 가독성이 높다.
- 트리나 그래프 탐색과 같은 계층적 문제 해결에 적합하다. - 단점
- 반복적으로 호출되므로 성능이 떨어질 수 있다.
- 스택 메모리를 과도하게 사용할 경우 문제가 발생한다.
재귀 함수의 구조
void recursiveFunction(매개변수) {
if (기본 조건) {
// 기본 조건에 도달하면 종료
return;
} else {
// 재귀 조건
recursiveFunction(변경된 매개변수);
}
}
예제
1. 팩토리얼(Factorial)
- 정의: n! = n x (n - 1)!
- 기본 조건: 0! = 1
int factorial(int n) {
if (n == 0) { // 기본 조건
return 1;
} else { // 재귀 조건
return n * factorial(n - 1);
}
}
2. 피보나치 수열(Fibonacci Sequence)
- 정의: F(n) = F(n - 1) + F(n - 2)
- 기본 조건: F(0) = 0, F(1) = 1
int fibonacci(int n) {
if (n == 0) {
return 0;
} else if (n == 1) {
return 1;
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
시간 복잡도
- 팩토리얼: O(n)
- 피보나치 수열: O(2ⁿ) (중복 계산 발생)
=> 해결 방법: 메모이제이션(Memoization) 또는 동적 프로그래밍(Dynamic Programming)을 사용하여 최적화
반복문과 재귀 비교
구분 | 재귀 | 반복문 |
코드 간결성 | 간결하고 직관적 | 코드가 길어질 수 있음 |
성능 | 스택 메모리 사용으로 비효율적 | 반복문 사용으로 효율적 |
적용성 | 트리, 그래프 등 계층적 문제 | 단순 반복 작업에 적합 |
디버깅 난이도 | 호출 스택 추적 어려움 | 비교적 쉽다 |
Tail Recursion(꼬리 재귀)
Tail Recursion은 재귀 호출이 함수의 마지막 작업인 경우를 말한다.
컴파일러가 이를 반복문으로 최적화하여 스택 메모리 사용을 최소화할 수 있다.
예제
int tailFactorial(int n, int result) {
if (n == 0 ) {
return result;
}
return tailFactorial(n - 1, n * result);
}
'CS' 카테고리의 다른 글
[자료구조] 정렬(Sorting) (0) | 2024.12.03 |
---|---|
[자료구조] 스택과 큐(Stack & Queue) (0) | 2024.11.30 |
[자료구조] 배열 & 연결리스트(Array & LinkedList) (0) | 2024.11.29 |
[Linux/Unix] 저수준 파일 입출력 (0) | 2023.04.08 |
[Linux/Unix] 명령행 인자 (0) | 2023.04.08 |