Recent Posts
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 달인막창
- python
- 헥사고날아키텍처 #육각형아키텍처 #유스케이스
- 코루틴 빌더
- Spring Batch
- kotlin
- taint
- tolerated
- JanusWebRTCGateway
- vfr video
- 깡돼후
- 개성국밥
- Value too long for column
- JanusWebRTCServer
- VARCHAR (1)
- 티스토리챌린지
- mp4fpsmod
- JanusGateway
- pytest
- 자원부족
- 겨울 부산
- 오블완
- terminal
- JanusWebRTC
- 코루틴 컨텍스트
- preemption #
- table not found
- PytestPluginManager
- k8s #kubernetes #쿠버네티스
- PersistenceContext
Archives
너와 나의 스토리
[Kotlin] 재귀 함수를 꼬리 재귀 함수로 변환하여 최적화하는 방법 (tailrec 사용) 본문
Programming Language/Kotlin
[Kotlin] 재귀 함수를 꼬리 재귀 함수로 변환하여 최적화하는 방법 (tailrec 사용)
노는게제일좋아! 2021. 9. 10. 10:20반응형
꼬리 재귀 함수와 tailrec 설명 바로 가기
예제 1: 정수 리스트에 들어 있는 모든 원소의 합계를 구하는 함수
- 먼저 간단하게 구현하면 다음과 같다.
-
fun sum(list: List<Int>): Int = if (list.isEmpty()) 0 else list[0] + sum(list.drop(1))
- 코드는 간단하지만 빈 리스트를 만날 때까지 스택에 메모리가 계속 쌓이게 된다.
- 이 함수는 꼬리 재귀가 아니기 때문에 tailrec 키워드를 붙일 수 없고, 리스트 인자가 몇천 개 이상이면 이 함수를 사용할 수 없다.
-
- 이 함수를 꼬리 재귀 함수로 만들어보자.
-
fun sum(list: List<Int>): Int { tailrec fun sum_(list: List<Int>, acc: Int): Int = if (list.isEmpty()) acc else sum_(list.drop(1), acc + list[0]) return sum_(list, 0) }
- sum_ 도우미 함수는 꼬리 재귀 함수이므로 TCE를 통해 최적화가 가능하다.
- 참고: 내부 도우미 함수 네이밍
- 1. go, process 같은 이름으로 통일
- 2. sum_처럼 주 함수 이름 뒤에 밑줄을 붙이기
- 어떤 방식이든 항상 일관성을 지키는 것이 중요
-
예제 2: 피보나치 수열을 구하는 함수
- 먼저 이중 재귀 함수로 간단하게 구현해보자.
-
fun fibonacci(number: Int): Int = if (number <= 1) 1 else fibonacci(number - 2) + fibonacci(number - 1)
- 위 함수는 한 번 호출될 때마다 재귀 호출이 두 개씩 더 생긴다.
- 즉, f(n)을 계산하려면 $2^n$ 개의 재귀 호출이 발생한다.
-
- 사용할 수 있는 피보나치 함수를 만들려면 이 함수가 꼬리 재귀를 단 하나만 사용하도록 바꿔야 한다.
- 또한, n이 조금만 커져도 f(n) 값이 너무 커지기 때문에 큰 값을 처리하는 파라미터 타입으로 변경해 줘야 한다.
- 꼬리 재귀 버전의 피보나치 함수:
-
fun fibonacci(number: Int): BigInteger { tailrec fun fibonacci_(val1: BigInteger, val2: BigInteger, x: BigInteger): BigInteger = when { x == BigInteger.ZERO -> BigInteger.ONE x == BigInteger.ONE -> val1+val2 else -> fibonacci_(val2, val1 + val2, x - BigInteger.ONE) } return fibonacci_(BigInteger.ZERO, BigInteger.ONE, BigInteger.valueOf(number.toLong())) }
- 다음과 같이 이중 재귀를 단일 공재귀로 바꿈으로써 성능이 월등히 향상되었다.
-
반응형
'Programming Language > Kotlin' 카테고리의 다른 글
Kotlin coding convention 정리 (0) | 2022.07.01 |
---|---|
[Kotlin] takeIf & takeUnless (0) | 2022.06.19 |
[Kotlin] 재귀 함수 값(val) 사용하기, 재귀 함수 초기화 문제 해결 by lazy (0) | 2021.09.06 |
[Kotlin] 재귀 함수의 꼬리 호출 제거(TCE): tailrec 키워드 (0) | 2021.09.06 |
[Kotlin] 안전하게 프로그래밍 하기 (0) | 2021.08.23 |
Comments