美文网首页
每天学一点 Kotlin -- 函数:尾递归函数

每天学一点 Kotlin -- 函数:尾递归函数

作者: 冯可乐同学 | 来源:发表于2021-10-29 07:22 被阅读0次

----《第一季Kotlin崛起:次世代Android开发 》学习笔记

总目录:每天学一点 Kotlin ---- 目录
上一篇:每天学一点 Kotlin -- 函数:字面量
下一篇:每天学一点 Kotlin -- 函数:标准库函数

1. 尾递归函数

1.1 递归函数:当特定的目标没有完成时,函数一直在自己调用自己。

1.2 但是递归也有弊端,就是在完成最后一次递归前会占用大量的资源和内存。所以递归用的较少。而且能用递归实现的功能,用循环肯定也能实现。

1.3 如果一个递归函数的调用可以简化到使用一个特殊函数作为最后一次操作,且调用的结果是一个返回值,那么系统就不会保持上一次操作的内存堆栈。因此就不需要其他临时变量来维持进一步操作,直接返回这个特殊函数调用的值即可。这种技术被称为尾递归。运用尾递归可以写出高效的递归算法,从而避免堆栈溢出错误 ---- 尾递归是对递归的优化。

1.4 要在 Kotlin 中使用一个尾递归函数,可以用 tailrec 关键字定义函数。如此,编译器便可以确信每一次递归使用这个函数作为最后一次操作。

1.5 举个栗子1:

fun main() {
    println(fact(5))
    println(fact2(5))
}
fun fact(k: Int): Int {
    println("k = " + k)
    if (k == 1) {
        return 1
    } else {
        var re = k * fact(k - 1)
        println("re = " + re)
        return re
    }
}

fun fact2(k: Int): Int {
    fun tailFact2(m: Int, n: Int): Int {
        println("m = " + m + ", n = " + n)
        if (m == 1) {
            return n
        } else {
            var re = tailFact2(m - 1, m + n)
            println("re = " + re)
            return re
        }
    }

    return tailFact2(k, 1)
}

打印结果:

普通的递归:
k = 5
k = 4
k = 3
k = 2
k = 1
re = 2
re = 6
re = 24
re = 120
120
使用尾递归的递归: 
m = 5, n = 1
m = 4, n = 6
m = 3, n = 10
m = 2, n = 13
m = 1, n = 15
re = 15
re = 15
re = 15
re = 15
15

可以看出,两个函数计算的结果是一样的,区别在于:
---- 普通的递归中,参数全部被保存下来,知道最后一层调用中计算得到结果后,再依次倒退和参数相加得到最终的结果
---- 在尾递归中,在 var re = tailFact2(m - 1, m + n) 这一行代码中,每次向下调用自身时都已经计算出结果了,直接把本次的结果向下计算,不需要保存之前的入参参数了。

1.6 举个栗子2:

fun main(args: Array<String>){
    println("普通的递归:start: " + System.currentTimeMillis())
    println("普通的递归:result = " + fibo(40))
    println("普通的递归:end: " + System.currentTimeMillis())

    println("使用尾递归的递归: start: " + System.currentTimeMillis())
    println("使用尾递归的递归:result = " + fibo2(40))
    println("使用尾递归的递归: end: " + System.currentTimeMillis())
}

// 之前的递归
fun fibo(startNum: Int): Int = when(startNum){
    0 -> 1
    1 -> 1
    else -> fibo(startNum - 1) + fibo(startNum - 2)
}

// 使用尾递归
fun fibo2(startNum: Int): Int{
   tailrec fun fiboTail(index: Int, ant: Int, act: Int): Int =
           when(index){
               0 -> ant
               else -> fiboTail(index - 1, act, ant + act)
           }

    return fiboTail(startNum, 1, 1)
}

打印结果:

普通的递归:start: 1634804071403
普通的递归:result = 165580141
普通的递归:end: 1634804071740
使用尾递归的递归: start: 1634804071740
使用尾递归的递归:result = 165580141
使用尾递归的递归: end: 1634804071740

可以看出,尾递归相比较与普通的递归,优化效果还是很明显的。

相关代码:https://gitee.com/fzq.com/test-demo

相关文章

  • 每天学一点 Kotlin -- 函数:尾递归函数

    1. 尾递归函数 1.1 递归函数:当特定的目标没有完成时,函数一直在自己调用自己。 1.2 但是递归也有弊端,就...

  • Kotlin中的函数

    Kotlin中的函数 kotlin中的函数分为普通函数,泛型函数,内联函数,扩展函数,高阶函数以及尾递归函数 1 ...

  • kotlin精讲-第2章(11)kotlin函数加强_下

    Kotlin相比于Java 目标 尾递归函数 我们首先说递归函数,什么是递归函数呢?递归函数指的的在方法体内部还去...

  • Kotlin 函数用法入门

    本文内容: 函数与函数常量 扩展函数 命名参数与默认参数 运算符重载 递归与尾递归 定义函数 在 Kotlin 中...

  • 1

    #函数 ##递归函数容易,栈溢出,这个时候可以用*尾递归*优化,尾递归的意思就是说在递归函数末尾引用本函数的时候,...

  • python学习4

    学廖雪峰老师的python教程笔记。 1、递归函数 函数内部调用该函数本身,比循环逻辑简单 注意防止栈溢出 尾递归...

  • 2018-07-28

    递归函数以及尾递归优化: #利用递归函数计算阶乘 ... #N! = 1 * 2 * 3 * 4 * ... * ...

  • 尾递归

    函数调用自身,称为『递归』;函数尾调用自身,称为『尾递归』 由于递归需要保存大量调用帧,很消耗内存,容易发生 st...

  • 重复

    递归在自己的定义中调用自己的函数叫做递归函数(Recursive Function)。 尾递归普通的递归调用并不高...

  • 理解装饰器的各种执行细节

    当装饰器遇上尾递归函数 如果一个尾递归函数套用了装饰器,那么当一次递归发生后,是尾递归内部的代码先执行,还是装饰器...

网友评论

      本文标题:每天学一点 Kotlin -- 函数:尾递归函数

      本文链接:https://www.haomeiwen.com/subject/rgetaltx.html