参考
https://www.cnblogs.com/bakari/p/5349383.html
https://blog.csdn.net/tong_xin2010/article/details/38686911
https://blog.csdn.net/h330531987/article/details/76218956
#include <stdio.h>
//目的是把一个整数从二进制形式转换为可打印的字符形式
//采用的策略是把这个值反复除以10,并打印各个余数
int binary_to_ascii( unsigned int value)
{
unsigned int quotient;
quotient = value / 10;
if( quotient != 0)
binary_to_ascii( quotient);
putchar ( value % 10 + '0' );
}
执行过程的堆栈过程
递归的效率
递归导致一个函数反复调用自己,我们知道函数调用是通过一个工作栈来实现的,在大多数机器上,每次调用函数时大致要做三个工作:调用前先保存寄存器,并在返回时恢复;复制实参;程序必须转向一个新位置执行。其中,具体要保存的内容包括:局部变量、形参、调用函数地址、返回值。那么,如果递归调用N次,就要分配N局部变量、N形参、N调用函数地址、N返回值。这势必是影响效率的。在C++中,inline函数就是为了改善函数调用所带来的效率问题而做的一种优化。递归就是利用系统的堆栈保存函数当中的局部变量来解决问题的,说白了就是利用堆栈上的一堆指针指向内存中的对象,并且这些对象一直不被释放,直到遇到简单情境时才一一出栈释放,所以总的开销就很大。栈空间都是有限的,如果没有设置好出口,或者调用层级太多,有可能导致栈空间不够,而出现栈溢出的问题。为了防止无穷递归现象,有些语言是规定栈的长度的,比如python语言规定堆栈的长度不能超过1000。还有就是当规模很大的时候,尽量不使用递归,而改为非递归的形式,或者优化成尾递归的形式。
什么是尾递归
如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的。当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归。尾递归函数的特点是在回归过程中不用做任何操作,这个特性很重要,因为大多数现代的编译器会利用这种特点自动生成优化的代码。
//线性递归
long Rescuvie(long n) {
return (n == 1) ? 1 : n * Rescuvie(n - 1);
}
//尾递归
/*facttail.c*/
#include"facttail.h"
/*facttail*/
int facttail(int n, int a)
{
/*Compute a factorialina tail - recursive manner.*/
if (n < 0)
return 0;
else if (n == 0)
return 1;
else if (n == 1)
return a;
else
return facttail(n - 1, n * a);
}
递归转尾递归
尾递归其实是将普通递归转换成一种迭代的形式,下一层递归所用的栈帧可以与上一层有重叠,局部变量可重复利用,不需要额外消耗栈空间,也没有push和pop。 使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况,这样就大大减少了递归调用栈的开销。和循环效果差不多。
能不能优化主要看编译器支持不支持,不能优化的话,那一样会导致栈溢出。
尾递归的优势
不会溢出,效率和递归差不多