오늘은 재귀에 대해 설명 드리겠습니다.
커리큘럼은 아래와 같습니다.
재귀의 정의
재귀의 예시 - 팩토리얼
재귀의 예시 - 하노이 탑
재귀를 사용할 때 조심해야 하는 경우
저자카톡방 : https://open.kakao.com/o/gX0WnTCf
저자 카페 : https://cafe.naver.com/dremdeveloper
재귀 함수(recursion function)의정의 2/2
재귀함수는, 재귀의 정의에 아래조건 추가 필요
- 프로그래밍의 재귀는 무한한 재귀를 가지지 않는다.
반드시 base case가 존재한다.
- 같은 문제를 좀 더 간단한 문제로 감소 시키는 방식으로 동작한다.
f f f f
base case
바로 풀 수 있는 문제
팩토리얼의 정의 1/6
N!은N부터 숫자를 하나씩 줄여가며 1 까지 모두 곱한 수
1!
2!
3!
N!
1
2 1
3 2 1
*
* *
N (N-1) (N-2)
* * 1
…
=
=
=
=
12.
팩토리얼의 정의 -반복문 2/6
3 1
N answer
3
2
1*3
3-1
6
1
3*2
2-1
6
0 1-1 exit while
반환
N=3
N=2
N=1
N=3일때 실제 동작
13.
팩토리얼의 정의 -반복문을 재귀로 변경해보자 3/6
1. 더 간단히 더 작게(Simpler & Smaller)
2. base case는 어떻게 될 것인가?
1!
2!
3!
1
2 1
3 2 1
*
* *
=
=
=
3!을 구할때 2!가 그대로 활용됨
2!을 구할때 1!가 그대로 활용됨
14.
팩토리얼의 정의 -반복문을 재귀로 변경해보자 4/6
N으로 일반화 하면 아래와 같이도 나타낼 수 있다.
무한히 호출하지 않은 1!이라는 base case 존재
여전히 팩토리얼 문제이지만, 문제크기가 줄어들고 있음
15.
팩토리얼의 정의 -반복문을 재귀로 변경해보자 5/6
있다고 믿는다는게 말이 됩니까!
- 네, 이미 내부 구현은 여러분들이 설계 했습니다. 점화식을 넣으면 됩니다.
16.
팩토리얼의 정의 -반복문을 재귀로 변경해보자 6/6
실제 재귀함수의 호출과정을 그리면 아래와 같습니다.
base case
하노이탑 게임 정의1/11
3개의 기둥이 있고, 첫 번째 기둥에 길이가 긴 막대부터 차례대로 쌓아있다.
아래 규칙에 따라 세번 째 기둥에 모든 막대를 옮겨야 한다.
- 길이가 긴 막대가 길이가 짧은 막대 위에 있을 수 없다.
- 한번에 하나의 기둥만 옮길 수 있다.
첫 번째 기둥 두 번째 기둥 세 번째 기둥
하노이 탑 -재귀로 구현해보자 6/11
1. 더 간단히 더 작게(Simpler & Smaller)
2. base case는 어떻게 될 것인가?
24.
하노이 탑 -재귀로 구현해보자(con’t d) 7/11
1 > 3 1 > 2 3 > 2
막대가 3개일 때 구하는 과정을 하나씩 쪼개서 봅시다
결국 막대 2개를 옮기는 연산과 같다
=> 하노이 탑에서 막대 2개 문제의 해로 해결 가능
25.
하노이 탑 -재귀로 구현해보자(con’t d) 8/11
막대가 3개일 때 구하는 과정을 하나씩 쪼개서 봅시다
결국 막대 1개를 옮기는 연산과 같다
=> 하노이 탑 막대 1개 문제의 해로 해결 가능
1 > 3
26.
하노이 탑 -재귀로 구현해보자(con’t d) 9/11
막대가 3개일 때 구하는 과정을 하나씩 쪼개서 봅시다
결국 막대 2개를 옮기는 연산과 같다
=> 하노이 탑 막대 2개 문제의 해로 해결 가능
2 > 1 1 > 3
2 > 3
27.
1. 첫 번째기둥의 맨 밑의 막대를 제외하고, 위에 있는 2개의 막대를 두 번째 기둥에 옮깁니다.
2. 첫 번째 기둥의 맨 밑의 막대를 세 번째 기둥에 옮깁니다.
3. 두 번째 기둥에 있는 막대 2개를 세 번째 기둥에 옮깁니다.
1. 첫 번째 기둥의 맨 밑의 막대를 제외하고, 위에 있는 1개의 막대를 두 번째 기둥에 옮깁니다.
2. 첫 번째 기둥의 맨 밑의 막대를 세 번째 기둥에 옮깁니다.
3. 두 번째 기둥에 있는 막대 1개를 세 번째 기둥에 옮깁니다.
1. 첫 번째 기둥의 맨 밑의 막대를 제외하고, 위에 있는 1개의 막대를 두 번째 기둥에 옮깁니다.
2. 첫 번째 기둥의 맨 밑의 막대를 세 번째 기둥에 옮깁니다.
3. 두 번째 기둥에 있는 막대 1개를 세 번째 기둥에 옮깁니다.
막대가 3개인 문제
막대가 2개인 문제
막대가 2개인 문제
1 2 3
1 3 2
: 막대 1개인 문제(base case)
하노이 탑 - 문제가 축소되는 과정 10/11
28.
하노이 탑 -최종 구현 11/11
1. 더 간단히 더 작게(Simpler & Smaller)
=> (N-1)개의 막대를 옮기는 문제 + 막대 1개를 옮기는 문제로 축소
* (N-1)개의 막대를 1번째 기둥에서 2 번째 기둥으로 옮김
* 첫 번째 기둥 맨 아래 막대를 3번째 기둥으로 옮김
* 두 번째 기둥의 (N-1)개의 막대를 3 번째 기둥으로 옮김
2. base case는 어떻게 될 것인가?
=> 막대 1개를 옮기는 문제(그냥 옮기면 됨)
막대 번호 옮길 막대 개수
출력값
1->3
1->2
3->2
1->3
2->1
2->3
1->3
재귀 사용시 주의할점 - 실제 재귀호출 모습
한 개의 fibonacci함수는, 두 개의 fibonacci를 호출하는 구
조이므로 호출횟수가 지수적으로 증가함
fibonacci(N)은 대략 2^(N-1)번 함수를 호출 함
이 부분은 코드에 잘 드러나지 않음!!
fibonacci(4)
34.
재귀 사용시 주의할점
1. 실제 코드 동작시 함수 호출이 얼마나 되는지 드러나지 않음
=> 재귀를 구현할 때 호출 횟수가 많이 증가하는 경우, recursion depth를 초과하지 않는지 확인 필요
2. 런타임 에러 발생시 에러가 코드에 명확히 보이지 않음
=> 복잡한 재귀함수는 반복문으로 작성 고려
재귀는 잘 사용할 경우, 코드를 간결하게 해주고 가독성을 높여 주지만, 명확하게 recursion depth를 고민하고 사용
하지 않으면 런타임 에러가 발생할 수 있습니다.
처음 연습하는 분들은 꼭 ppt처럼 call trace를 그림으로 작성해보시고 구현해주세요