#5. мемоизированная реализация рекурсивного алгоритма Фибоначии.

Приветствую читатель!

Сегодня приведу пример мемоизированной реализации рекурсивного алгоритма Фибоначии. Мемоизация позволяет ускорить вычисления за счет того, что, не выполняет повторно вычисления для уже ранее вычисленных и сохраненных аргументов.

Листинг из книги: Пьер-Ив Симон: Волшебство Kotlin

Kotlin
import java.math.BigInteger

fun main() {

    val result = fibo(5)
    println(result)

}

fun fibo(number: Int): String {

    tailrec fun fibo(
        acc: List<BigInteger>,
        acc1: BigInteger,
        acc2: BigInteger,
        x: BigInteger
    ): List<BigInteger> =
        when (x) {
            BigInteger.ZERO -> acc
            BigInteger.ONE -> acc + (acc1 + acc2)
            else -> fibo(acc + (acc1 + acc2), acc2, acc1 + acc2, x - BigInteger.ONE)
        }

    val list = fibo(
        listOf(),
        BigInteger.ONE,
        BigInteger.ZERO,
        BigInteger.valueOf(number.toLong())
    )
    return makeString(list, ", ")
}

fun <T> List<T>.head(): T =
    if (this.isEmpty())
        throw IllegalArgumentException("head called on empty list")
    else
        this[0]

fun <T> List<T>.tail(): List<T> =
    if (this.isEmpty())
        throw IllegalArgumentException("tail called on empty list")
    else
        this.drop(1)

fun <T> makeString(list: List<T>, separator: String): String =
    when {
        list.isEmpty() -> ""
        list.tail().isEmpty() -> list.head().toString()
        else -> list.head().toString() +
                foldLeft(list.tail(), "") { x, y -> x + separator + y }
    }

fun <T, U> foldLeft(list: List<T>, z: U, f: (U, T) -> U): U {
    tailrec fun foldLeft(list: List<T>, acc: U): U =
        if (list.isEmpty())
            acc
        else
            foldLeft(list.tail(), f(acc, list.head()))
    return foldLeft(list, z)
}