例题1 阶乘函数
int func(int n){ if(n<0) return -1; if(n==0) return 1; return n*func(n-1); }
一个完整的阶乘函数应该像上面一样写,一般的书都是默认了输入的时候不会输出超过范围的数字,但是我们自己写程序的时候,应该要考虑所有的情况。一个递归应该能让所有输入的值都有一个出口。
所以一般来说,递归应该由三个部分组成:递归体(自己调用自己),递归出口,和容错。
例题2 斐波那契数列
int func(int n){ if(n<0) return -1; if(n==1) return 1; return func(n-1)+func(n-2); }
这两个例题,都是最基本的递归入门函数。但假如,我们要使用不支持递归的语言去实现递归的作用,那我们应该?
对于任何递归函数,都存在功能等价的迭代实现。
所以让我们试着,把上面两个任务,都用迭代的方法去实现:
阶乘函数:
int func(int n){ int p=1; for(int i=2;p<=n;i++){ p=p*(i-1) } return p; }
斐波那契数列:
int func(int n){ int a=1,b=1,c=1; for(int i=2;i<=n;i++){ c = a+b; b = c; a = b; } return c; }
那么此时,问题来了?我们不可能同时写两种方法,我们应该如何选择更好的写法?
对于例题一来说,递归函数,要计算n次,时间复杂度是O(n),空间复杂度也是O(n)。迭代的方法呢,计算n次,时间复杂度是O(n),空间复杂度是O(1),自己新用到了一个变量,所以两个的差别并不大,都可以选择。
对于例题二来说,递归函数,我们可以画一个类似于二叉树的模型,根据规律大概可以估算它每次给n加1,计算就要翻倍,实际是要计算大概1.618的n次方次,所以时间复杂度大概是O(2^n)次,而空间复杂度也差不多是这样,根据实际的测算,计算n=100的时候,就等到咱去世了也没有结果0_0,可以说是一个并没什么用的程序了。而对迭代函数来说,还是计算n次,空间复杂度也是n(1),所以这时候,迭代的效率要高很多。
所以我们对比也得到了递归函数的优点和缺点,优点是易理解方便,缺点是性能差,原因有两个:1.必须递归栈的支持;2.可能出现子问题重叠现象。