递归(Recursive)是指自己方法内部调用自己
如求 1- n(n>1)之间的和:
public static long sum(long n) {
if (n == 1) {
return 1;
}
return n + sum(n - 1);
}
这是使用递归的方式求和,很消耗内存,比如我求 1 - 2147483647 ( Integer.MAX_VALUE ) ,就会StackOverflowError ,堆栈溢出
但是其实使用循环是可以计算出的
static long sum(long n){
long res = 0;
while (n > 0){
res+=n;
n--;
}
return res;
}
继续求 1 - 2147483647 ( Integer.MAX_VALUE ) 的和
第二行是结果,第三行是用时
那么什么是尾递归呢?
就是递归时只返回函数本身,没有其他计算
即:
static long sum(long n,long sum){
if (n == 0){
return sum;
}
return sum(n - 1,n+sum);
}
在某些语言中,写成这样的递归在编译时会被自动优化,或者运行时会清除上次的栈信息,因为上次执行中的任何数据在下次执行时都是无关的
那么在 java上既然可能会出现问题,那么在使用递归时需要注意,尽量使用循环,或者在计算很小的数据时使用
在kotlin中,我们写成尾递归的时候,配合关键字 tailrec
如下:
tailrec fun sum(n: Int, res: Long): Long {
if (n == 0) {
return res;
}
return sum(n - 1, res + n)
}
测试代码
fun main(args: Array<String>) {
val start = System.currentTimeMillis()
val result = sum(Int.MAX_VALUE, 0)
val end = System.currentTimeMillis()
println(result)
println("time:${end - start}")
}
结果和上面使用循环的结果一致
时间上好像变短了。。。
反编译kotlin生成的class文件
现在测试不加 tailrec 试试
一样会溢出
再次反编译class查看
代码并没有做优化
因此在使用 kotlin 时,可以使用关键字 tailrec 来进行优化尾递归
注意:必须是尾递归!!!
而使用 java编写时,尽量避免使用递归做深度的计算,可以使用循环代替!