위키백과 에서는 컴퓨터 과학에서의 재귀를 아래와 같이 정의한다.
컴퓨터 과학에 있어서 재귀(再歸, Recursion)는 자신을 정의할 때 자기 자신을 재참조하는 방법을 뜻하며, 이를 프로그래밍에 적용한 재귀 호출(Recursive call)의 형태로 많이 사용된다.
재귀 함수(Recursion)는 함수에서 자기 자신을 다시 호출해 작업을 수행하는 방식이다.
특정 분기 전까지 자기 자신을 계속해서 호출하는데, 주로 반복문을 구현할 때 사용한다.
def factorial(n):
if n == 1: # base case
return 1
return n*factorial(n-1) # recursive case
- 함수의 정의
- base condition
- 재귀 식
재귀 함수에서는 재귀 호출을 종료해주는 종료 조건(base case)이 중요하다.
def factorial(n):
return n*factorial(n-1) # 반복적으로 실행되는 부분
이렇게 if문이 빠지게 되면, 함수는 멈추지 않고 -1, -2, ..., -n까지 무한하게 실행하게 된다.
파이썬에서는 최대 재귀 깊이(maximum recursion depth)가 1,000
으로 정해져 있어, 최대 재귀 깊이를 초과하면 RecursionError
가 발생한다.
import sys
sys.setrecursionlimit(100000) # 최대 재귀 깊이 변경
print(sys.getrecursionlimit()) # 설정된 최대 재귀 깊이 확인
자바나 C++에서도 메모리의 한계를 초과하면 StackOverflowError
가 발생한다.
재귀 함수의 단점을 해결하기 위해 꼬리 재귀(tail call recursion)
이라는 기법이 있다.
이는 컴파일러가 꼬리 재귀 코드를 보고, 적절한 반복문으로 컴파일을 해주어 동작하는 방법이다.
# Basic recursion
def factorial(n):
if n == 1:
return 1
return n*factorial(n-1)
# Tail call recursion
def factorial(n, total):
if n == 1:
return 1
return factorial(n-1, n*total)
꼬리 재귀에서는 재귀 호출이 끝나는 시점에서 아무 일도 하지 않고 바로 결과를 반환하도록하여 함수의 상태 유지 및 추가 연산을 하지 않아 스택 오버 플로우 문제를 해결할 수 있다.
위 코드에서 차이점을 보면 반환 부에서 연산이 없어진 것을 볼 수 있다.