尾递归优化

尾递归优化是利用上面的第一个特点“调用同一个方法”来进行优化的 
尾递归优化其实包括两个东西:1)尾递归的形式;2)编译器对尾递归的优化 
尾递归的形式 
尾递归其实只是一种对递归的特殊写法,这种写法原本并不会带来跟递归不一样的影响,它只是写法不一样而已,写成这样不会有任何优化效果,该爆的栈和帧都还会爆 
具体不一样在哪里 
前面说了,递归的本质是某个方法调用了自身,尾递归这种形式就要求:某个方法调用自身这件事,一定是该方法做的最后一件事(所以当有需要返回值的时候会是return f(n),没有返回的话就直接是f(n)了) 
要求很简单,就一条,但是有一些常见的误区 
这个f(n)外不能加其他东西,因为这就不是最后一件事了,值返回来后还要再干点其他的活,变量空间还需要保留 
比如如果有返回值的,你不能:乘个常数 return 3f(n);乘个n return n*f(n);甚至是 f(n)+f(n-1) 
另外,使用return的尾递归还跟函数式编程有一点关系 
编译器对尾递归的优化 
上面说了,你光手动写成尾递归的形式,并没有什么卵用,要实现优化,还需要编译器中加入了对尾递归优化的机制 
有了这个机制,编译的时候,就会自动利用上面的特点一来进行优化 
具体是怎么优化的: 
简单说就是重复利用同一个栈帧,不仅不用释放上一个,连下一个新的都不用开,效率非常高(有人做实验,这个比递推比迭代都要效率高) 
为什么写成尾递归的形式,编译器就能优化了?或者说【编译器对尾递归的优化】的一些深层思想 
说是深层思想,其实也是因为正好编译器其实在这里没做什么复杂的事,所以很简单 
由于这两方面的原因,尾递归优化得以实现,而且效果很好 
因为在递归调用自身的时候,这一层函数已经没有要做的事情了,虽然被递归调用的函数是在当前的函数里,但是他们之间的关系已经在传参的时候了断了,也就是这一层函数的所有变量什么的都不会再被用到了,所以当前函数虽然没有执行完,不能弹出栈,但它确实已经可以出栈了,这是一方面 
另一方面,正因为调用的是自身,所以需要的存储空间是一毛一样的,那干脆重新刷新这些空间给下一层利用就好了,不用销毁再另开空间 
有人对写成尾递归形式的说法是【为了告诉编译器这块要尾递归】,这种说法可能会导致误解,因为不是只告诉编译器就行,而是你需要做优化的前半部分,之后编译器做后半部分 
所以总结:为了解决递归的开销大问题,使用尾递归优化,具体分两步:1)你把递归调用的形式写成尾递归的形式;2)编译器碰到尾递归,自动按照某种特定的方式进行优化编译

https://blog.csdn.net/yan_chou/article/details/59488871

斐波那契数列

 常规的斐波那契数列算法可能是这样的:

1
2
3
4
5
6
7
int  fib( int  n) {
 
     if  (n <= 2) {
         return  1;
     }
     return  fib(n - 1) + fib(n - 2);
}

  

上面的这种递归计算最终的return操作是加法操作。所以不是尾递归。

如果用尾递归就是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
  计算第n位斐波那契数列的值
  
  @param n 第n个数
  @param acc1 第n个数
  @param acc2 第n与第n+1个数的和
  @return 返回斐波那契数列值
  */
int  tailfib( int  n, int  acc1, int  acc2) {
     if  (n < 2) {
         return  acc1;
     }
     
     return  tailfib(n-1,acc2,acc1 + acc2); 
}

  

比如我们想计算第10位斐波那契数列的值,只需要fib(10,1,1)即可。

看一下测试效果,测试程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int  main( int  argc,  const  char  * argv[]) {
     clock_t start,finish;
    
     start = clock();
     printf( "计算结果:%d\n" , fib(45));
     finish = clock();
     printf( "花费时间--------%lu\n" ,finish - start);
 
     
     start = clock();
     printf( "计算结果:%d\n" , tailfib(45,1,1));
     finish = clock();
     
     printf( "花费时间--------%lu\n" ,finish - start);
     return  0;
     
}

  

计算结果如下:

1
2
3
4
5
计算结果:1134903170
花费时间--------5540692
计算结果:1134903170
花费时间--------4
Program ended with exit code: 0

  https://www.cnblogs.com/zhanggui/p/7722541.html

猜你喜欢

转载自www.cnblogs.com/feng9exe/p/9897923.html
今日推荐