线性递归: 即一般型的递归
一个函数直接或间接地调用自身,是为直接或间接递归,在调用过程中,需要压栈,可能会导致程序崩溃。
尾递归:
尾递归就是从最后开始计算, 每递归一次就算出相应的结果, 也就是说, 函数调用出现在调用者函数的尾部, 因为是尾部, 所以根本没有必要去保存任何局部变量. 直接让被调用的函数返回时越过调用者, 返回到调用者的调用者去.
例: 以阶乘来看两者的区别:
阶乘: 5!=1*2*3*4*5 结果为:120
线性递归:
long Rescuvie(long n)
{
return(n == 1) ? 1 : n * Rescuvie(n - 1);
}
调用过程如:
当n = 5时
对于线性递归, 他的递归过程如下:
Rescuvie(5)
开始调用
{5 * Rescuvie(4)}
{5 * {4 * Rescuvie(3)}}
{5 * {4 * {3 * Rescuvie(2)}}}
{5 * {4 * {3 * {2 * Rescuvie(1)}}}}
{5 * {4 * {3 * {2 * 1}}}}
{5 * {4 * {3 * 2}}}
{5 * {4 * 6}}
{5 * 24}
120
尾递归:
long TailRescuvie(long n, long a) {
return(n == 1) ? a : TailRescuvie(n - 1, a * n);
}
long TailRescuvie(long n) {//封装用的
return(n == 0) ? 1 : TailRescuvie(n, 1);
}
对于尾递归, 他的递归过程如下:
TailRescuvie(5)
TailRescuvie(5, 1)
TailRescuvie(4, 5)
TailRescuvie(3, 20)
TailRescuvie(2, 60)
TailRescuvie(1, 120)
120
一个函数直接或间接地调用自身,是为直接或间接递归,在调用过程中,需要压栈,可能会导致程序崩溃。
尾递归:
尾递归就是从最后开始计算, 每递归一次就算出相应的结果, 也就是说, 函数调用出现在调用者函数的尾部, 因为是尾部, 所以根本没有必要去保存任何局部变量. 直接让被调用的函数返回时越过调用者, 返回到调用者的调用者去.
例: 以阶乘来看两者的区别:
阶乘: 5!=1*2*3*4*5 结果为:120
线性递归:
long Rescuvie(long n)
{
return(n == 1) ? 1 : n * Rescuvie(n - 1);
}
调用过程如:
当n = 5时
对于线性递归, 他的递归过程如下:
Rescuvie(5)
开始调用
{5 * Rescuvie(4)}
{5 * {4 * Rescuvie(3)}}
{5 * {4 * {3 * Rescuvie(2)}}}
{5 * {4 * {3 * {2 * Rescuvie(1)}}}}
{5 * {4 * {3 * {2 * 1}}}}
{5 * {4 * {3 * 2}}}
{5 * {4 * 6}}
{5 * 24}
120
尾递归:
long TailRescuvie(long n, long a) {
return(n == 1) ? a : TailRescuvie(n - 1, a * n);
}
long TailRescuvie(long n) {//封装用的
return(n == 0) ? 1 : TailRescuvie(n, 1);
}
对于尾递归, 他的递归过程如下:
TailRescuvie(5)
TailRescuvie(5, 1)
TailRescuvie(4, 5)
TailRescuvie(3, 20)
TailRescuvie(2, 60)
TailRescuvie(1, 120)
120
尾递归易于在编译器层面优化。如果编译器未作优化,效果和线性递归差不多。
猴子吃桃问题:
猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾就多吃了一个。第二天早上又将剩下的桃子吃了一半,还是不过瘾又多吃了一个。以后每天都吃前一天剩下的一半再加一个。到第10天刚好剩一个。问猴子第一天摘了多少个桃子?
代码示例:
int sumPeach(int day) { if (day == 10) { return 1; } return 2 * sumPeach(day + 1) + 2; } int tailSumPeach(int day, int total) { if (day == 10) { return total; } return tailSumPeach(day + 1, 2 * total + 2); }