1. 概述

Fibonacci 数列 是指从第3项起,每一项都等于前两项之和的数列。其数学定义为:
*F(0) = 0, F(1) = 1, F(n) = F(n-1) + F(n-2)*。

常见的前几项为:0, 1, 1, 2, 3, 5, 8, 13, 21……(注意:本文示例从 F(1)=1 开始计算)

在 Kotlin 中,我们可以使用多种方式实现 Fibonacci 数列的生成。本文将介绍几种主流方法,涵盖递归、迭代、尾递归优化以及函数式编程风格,帮助你在不同场景下做出合理选择。

⚠️ 提示:虽然这是个经典算法题,但在实际开发中仍可能踩坑,比如性能问题或栈溢出,务必根据调用频率和输入规模谨慎选型。


2. 使用普通递归生成 Fibonacci

最直观的方式是直接按照数学公式实现递归:

fun fibonacciUsingRecursion(num: Int): Int {
    return if (num <= 1) {
        num
    } else {
        fibonacciUsingRecursion(num - 1) + fibonacciUsingRecursion(num - 2)
    }
}

✅ 实现简洁,逻辑清晰,完全对应数学定义。
❌ 时间复杂度高达 O(2^n),存在大量重复计算,不适合大数值输入

例如 fibonacciUsingRecursion(8) 会多次重复计算中间结果,效率极低。

测试验证:

@Test
fun `test checkIfFibonacciUsingRecursion return correct value`() {
    Assertions.assertThat(fibonacciUsingRecursion(8)).isEqualTo(21)
}

✅ 输出为 21,结果正确。但仅适用于小数据量演示或教学场景。


3. 使用迭代法优化性能

为了避免递归带来的性能开销,可以改用循环方式实现:

fun fibonacciUsingIteration(num: Int): Int {
    var a = 0
    var b = 1
    var tmp: Int
    for (i in 2..num) {
        tmp = a + b
        a = b
        b = tmp
    }
    return b
}

✅ 时间复杂度降为 O(n),空间复杂度 O(1),适合生产环境高频调用
✅ 无栈溢出风险,可处理较大输入值。

该方法通过维护两个变量 ab 来模拟状态转移,避免了函数调用堆栈的增长。

测试用例:

@Test
fun `test checkIfFibonacciUsingIteration return correct value`() {
    Assertions.assertThat(fibonacciUsingIteration(8)).isEqualTo(21)
}

💡 推荐作为默认实现方案,尤其在性能敏感的服务中。


4. 使用尾递归优化(Tail Recursion)

Kotlin 支持 tailrec 关键字对符合条件的递归进行编译期优化,将其转换为等价的循环结构,从而避免栈溢出。

tailrec fun fibonacciUsingTailRecursion(num: Int, a: Int = 0, b: Int = 1): Int {
    return if (num == 0) a else fibonacciUsingTailRecursion(num - 1, b, a + b)
}

✅ 利用了递归的可读性,同时获得迭代的性能优势。
✅ 编译器会自动优化为 while 循环,不会造成 StackOverflowError。
⚠️ 必须确保递归调用是函数最后一个操作,否则无法应用 tailrec

说明:

  • 参数 ab 用于传递前两项的值
  • 默认参数使得调用时无需传入初始状态:fibonacciUsingTailRecursion(8)

测试代码:

@Test
fun `test checkIfFibonacciUsingTailRecursion return correct value`() {
    Assertions.assertThat(fibonacciUsingTailRecursion(8)).isEqualTo(21)
}

✅ 这是在保持函数式风格前提下的高性能解法,推荐在函数式倾向项目中使用。


5. 函数式方式:使用 generateSequence

Kotlin 提供了强大的序列 API,可以通过 generateSequence() 实现惰性生成的 Fibonacci 序列:

fun fibonacciUsingSequence(num: Int): Int {
    val fibonacciSequence = generateSequence(Pair(1, 1)) { Pair(it.second, it.first + it.second) }
        .map { it.first }
    return fibonacciSequence.take(num).last()
}

✅ 风格优雅,符合函数式编程范式。
✅ 支持懒加载(lazy evaluation),适合流式处理或无限序列场景。
❌ 对简单需求略显“重”,且对理解函数式概念有一定门槛。

解析:

  • 起始种子为 Pair(1, 1) 表示前两项
  • 每次生成新 pair:(a, b) -> (b, a+b)
  • .map { it.first } 提取当前项
  • .take(num).last() 获取第 N 项

测试:

@Test
fun `test checkIfFibonacciSequence return correct value`() {
    Assertions.assertThat(fibonacciUsingSequence(8)).isEqualTo(21)
}

🎯 适用场景:需要生成整个序列、配合其他流操作(如 filter、transform)时非常方便。


6. 总结与建议

方法 时间复杂度 是否推荐 适用场景
普通递归 O(2^n) 仅教学演示
迭代法 O(n) ✅✅✅ 生产环境首选
尾递归 O(n) ✅✅ 函数式偏好项目
generateSequence O(n) 流式处理、惰性求值

📌 最终建议

  • 日常开发优先使用迭代法,稳定高效;
  • 若追求代码表达力且团队熟悉函数式,可选用尾递归或 sequence 方式
  • 绝对避免在服务中使用普通递归处理较大输入,容易引发性能瓶颈甚至服务雪崩。

所有示例源码已托管至 GitHub:https://github.com/Baeldung/kotlin-tutorials/tree/master/kotlin-math-2
可直接 clone 学习或集成测试。


原始标题:Fibonacci Series in Kotlin