Python - Python 함수에서 재귀호출 사용하기
Python
- Python 기본
- Python 숫자 계산하기
- Python 변수 만들기
- Python 출력 방법
- Python 불과 비교, 논리 연산자
- Python 문자열 사용하기
- Python 리스트와 튜플 사용하기
- Python 시퀀스 자료형 활용하기
- Python 딕셔너리 사용하기
- Python if 조건문으로 특정 조건일 때 코드 실행하기
- Python else를 사용하여 두 방향으로 분기하기
- Python elif를 사용하여 두 방향으로 분기하기
- Python for 반복문
- Python while 반복문
- Python break, continue로 반복문 제어하기
- Python 중첩루프
- Python FizzBuzz 문제
- Python 터틀 그래픽스로 그림 그리기
- Python 리스트와 튜플 응용하기
- Python 리스트와 튜플 응용하기 - 2
- Python 2차원 리스트 사용하기
- Python 문자열 응용하기
- Python 딕셔너리 응용하기
- Python 세트 사용하기
- Python 파일 사용하기
- Python 회문 판별과 N-gram 만들기
- Python 함수 사용하기
- Python 함수에서 위치 인수와 키워드 인수 사용하기
- Python 함수에서 재귀호출 사용하기
- Python 람다 표현식 사용하기
- Python 클로저 사용하기
- Python 클래스 사용하기
- Python 클래스 속성과 정적, 클래스 메서드 사용하기
- Python 클래스 상속 사용하기
- Python 두 점 사이의 거리 구하기
- Python 예외 처리 사용하기
- Python 이터레이터 사용하기
- Python 제너레이터 사용하기
- Python 코루틴 사용하기
- Python 데코레이터 사용하기
- Python 정규표현식 사용하기
- Python 모듈과 패키지 사용하기
- Python 모듈과 패키지 만들기
함수에서 재귀호출 사용하기
함수 안에서 함수 자기자신을 호출하는 방식을 재귀호출(recursive call)이라고 한다. 재귀 호출은 일반적인 상황에서는 잘 사용하지 않지만 알고리즘을 구현할 때 매우 유용하다. 보통 알고리즘에 따라서 반복문으로 구현한 코드보다 재귀호출로 구현한 코드가 좀 더 직관적이고 이해하기 쉬운 경우가 많다.
1. 재귀호출 사용하기
먼저 간단한 재귀호출 함수를 만들어보자. 다음 내용을 IDLE의 소스 코드 편집 창에 입력한 뒤 실행해보자.
def hello():
print('Hello, world!')
hello()
hello()
hello 함수 안에서 다시 hello 함수를 호출하고 있다. 소스 코드를 실행해보면 ‘Hello, world!’ 문자열이 계속 출력되다가 에러가 발생한다. 왜냐하면 파이썬에서는 최대 재귀 깊이(maximum recursion depth)가 1,000으로 정해져 있어서 그렇다. 즉, hello 함수가 자기자신을 계속 호출하다가 최대 재귀 깊이를 초과하면 RecursionError가 발생한다.
Hello, world!
Hello, world!
Hello, world!
...(생략)
Traceback (most recent call last):
File "C:\project\recursive_function_error.py", line 5, in <module>
hello()
File "C:\project\recursive_function_error.py", line 3, in hello
hello()
File "C:\project\recursive_function_error.py", line 3, in hello
hello()
File "C:\project\recursive_function_error.py", line 3, in hello
hello()
[Previous line repeated 974 more times]
File "C:\project\recursive_function_error.py", line 2, in hello
print('Hello, world!')
RecursionError: maximum recursion depth exceeded while pickling an object
재귀호출에 종료 조건 만들기
재귀호출을 사용하려면 반드시 다음과 같이 종료 조건을 만들어주어야 한다. 먼저 hello 함수의 반복 횟수를 계산하기 위해 매개변수 count를 지정다. 그리고 count가 0이면 hello 함수를 호출하지 않고 끝낸다. 만약 0이 아니면 ‘Hello, world!’를 출력하고, count의 값을 1씩 감소시킨 뒤 hello 함수를 호출할 때 넣어준다.
def hello(count):
if count == 0: # 종료 조건을 만듦. count가 0이면 다시 hello 함수를 호출하지 않고 끝냄
return
print('Hello, world!', count)
count -= 1 # count를 1 감소시킨 뒤
hello(count) # 다시 hello에 넣음 처음 5를 넣었다고 하면 hello(4)가 되고 점차 줄어든다.
hello(5) # hello 함수 호출
#결과
Hello, world! 5
Hello, world! 4
Hello, world! 3
Hello, world! 2
Hello, world! 1
2. 재귀호출로 팩토리얼 구하기
팩토리얼은 1부터 n까지 양의 정수를 차례대로 곱한 값이다. !(느낌표) 기호로 표기한다. 예를 들어 5!은 5 * 4 * 3 * 2 * 1이며 결과는 120이다. 재귀함수를 사용해 팩토리얼을 구현해 보자.
def factorial(n):
if n == 1: # n이 1일 때
return 1 # 1을 반환하고 재귀호출을 끝냄
return n * factorial(n - 1) # n과 factorial 함수에 n - 1을 넣어서 반환된 값을 곱함
print(factorial(5))
# 실행 결과
120
먼저 factorial 함수를 만들 때 매개변수 n을 지정해준다. 팩토리얼은 1부터 n까지의 곱을 구하는 문제인데 여기서는 n부터 역순으로 1씩 감소하면서 재귀호출을 하고 n이 1이 되었을때 재귀호출을 중단한다.
def factorial(n):
if n == 1: # n이 1일 때
return 1 # 1을 반환하고 재귀호출을 끝냄
factorial 함수의 핵심은 반환값 부분이다. 계산 결과가 즉시 구해지는 것이 아니라 재귀호출로 n - 1을 계속 전달하다가 n이 1일 때 비로소 1을 반환하면서 n과 곱하고 다시 결괏값을 반환한다. 그 뒤 n과 반환된 결괏값을 곱하여 다시 반환하는 과정을 반복한다.
return n * factorial(n - 1) # n과 factorial 함수에 n - 1을 넣어서 반환된 값을 곱함
factorial(5)를 호출해서 n이 1이 될 때까지 재귀호출하면 다음과 같은 모양이 된다. 왼쪽에서 오른쪽 순서이다.
5 * factorial | 5 * factorial | 5 * factorial | 5 * factorial | 5 * factorial |
---|---|---|---|---|
4 * factorial | 4 * factorial | 4 * factorial | 4 * factorial | |
3 * factorial | 3 * factorial | 3 * factorial | ||
2 * factorial | 2 * factorial | |||
factorial(1) return 1 |
이제 if n == 1:을 만나서 factorial 함수가 1을 반환한다. 그 뒤 1과 2를 곱해서 2를 반환하고, 3과 2를 곱해서 6을 반환하고, 4와 6을 곱해서 24를 반환하고, 5와 24를 곱해서 120을 반환하게 된다.
5 * factorial | 5 * factorial | 5 * factorial | 5 * factorial | 5 * factorial |
---|---|---|---|---|
4 * factorial | 4 * factorial | 4 * factorial | 4 * factorial | |
3 * factorial | 3 * factorial | 3 * factorial | ||
2 * factorial | 2 * factorial | |||
factorial(1) return 1 |
예제1
다음 소스 코드를 완성하여 문자열이 회문인지 판별하고 결과를 True, False로 출력되게 만드세요. 여기서는 재귀호출을 사용해야 합니다.
def is_palindrome(word):
_________________________
...
_________________________
print(is_palindrome('hello'))
print(is_palindrome('level'))
# 실행결과
False
True
답
if len(word) < 2: # 문자열의 길이가 2미만이면 True를 반환하고 재귀함수를 종료시킨다.
return True
if word[0] != word[-1]: # 첫 문자와 마지막 문자가 다르면 False를 출력하고 아니면 다음 줄로 이동
return False
return is_palindrome(word[1:-1]) #문자열의 1번인덱스 부터 -2인덱스 까지 넣어서 다시 함수에 넣는다. (문자열 슬라이싱에서 1:-1이면 마지막 인덱스의 전까지 가져온다.)
예제2
표준 입력으로 정수 한 개가 입력됩니다(입력 값의 범위는 10~30). 다음 소스 코드를 완성하여 입력된 정수에 해당하는 피보나치 수가 출력되게 만드세요.
피보나치 수는 0과 1로 시작하며, 다음 번 피보나치 수는 바로 앞의 두 피보나치 수의 합입니다.
# n
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21...
# 결과
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946...
________________
________________
________________
________________
________________
n = int(input())
print(fib(n))
#예
10
#결과
55
#예
20
#결과
6765
답
def fib(n):
if n <= 1:
return n
return fib(n-1)+fib(n-2)
#또는
def fib(n):
if n < 3: # 피보나치 수열의 2번쨰 까지 값이 1로 첫번째 값은 0이지만 영향을 주지 않아 값은 그대로 나옴
return 1
return fib(n-1)+fib(n-2)
#재귀함수를 사용하지 않은 코드
# 0 1 1 2 3 5 8 13 21 34 55 89
# fib(1) = [1], fib(2) = [1, 1] fib(3) = [1, 1, 2]
def fib(num):
result = []
first = 1
second = 1
if(num > 1):
result.append(first)
result.append(second)
for i in range(2, num):
third = first + second
result.append(third)
first = second
second = third
return result.pop()
print(fib(num))
피보나치 수열을 재귀함수로 해결하려면 결과와 정의를 잘 봐야한다. 재귀함수를 풀때는 역순으로 생각하는게 편하며 지문에서 말했듯이 ‘바로앞의 두 피보나치 수의 합이 다음 번 피보나치 수가 된다.’를 코드로 작성하면 fib(n) = fib(n-1)+fib(n-2) 이라는 것이다. 이 예제는 트리 형태를 띄고 있으며 10을 호출했을 경우를 풀어서 작성해보자. 각 함수 fib(n) 안에 다시 fib함수가 들어있는 형태이다.
- fib(10) = fib(9) + fib(8) (34+21 = 55)
- fib(9) = fib(8) + fib(7) (21+13 = 34)
- fib(8) = fib(7) + fib(6) (13+8 = 21)
- fib(7) = fib(6) + fib(5) (8+5 = 13)
- fib(6) = fib(5) + fib(4) (5+3 = 8)
- fib(5) = fib(4) + fib(3) (3+2 = 5)
- fib(4) = fib(3) + fib(2) (2+1 = 3)
- fib(3) = fib(2) + fib(1) (1+1 = 2)
- fib(2) = fib(1) + fib(0) (1+0 = 1)
- fib(1) = 1
Subscribe to My Coding Practice Gym
Get the latest posts delivered right to your inbox