尾递归很有意思~~~
拿快排说事的话,本来按照通俗易懂的理解,就是两次调用本身来进行左右排序。
按照尾递归的话得,可以省下一半的递归空间,直接拿一次的处理结果的low 或者high当参数传入下一次的调用。整个过程相比于同时进行两次本身的递归调用,这样只使用一次本身递归调用。
尾递归就是用迭代来代替递归全部过程。
递归调用会消耗大量的栈空间,每一次递归调用函数都会新开一个栈空间进行运行,同时要将上一次函数计算结果保存起来。所谓的保存现场,这样会消耗大量的栈空间。于是用迭代、用尾递归代替全递归调用就是一个很好的选择。
最常用距离都是斐波拉契数列,Feb(n) = n*(n-1)*(n-2)....2*1;
教科书就是用这个进行举例递归调用的。
function Feb($n){
if($n<=2)
{
return $n;
}
$res = $n*Feb($n-1);
return $res;
}
这样就是一个递归调用的最经典的例子,不过在计算的过程中,每次调用的时候都得将上次计算的过程进行现场保存。所以当n很大的时候,这个n会占用很大的内存。
所以改用迭代的过程,或者尾递归的过程,即把每次的计算的结果存储起来同时传递给下一次函数得调用。
function Febs($n,$sum){
if($n<=2)
{
return $sum;
}
else
{
return Febs($n-1,$sum*$n);
}
}
在快排改进排序中也是同样利用while迭代,来替代另外一次的递归调用。
function Partion(&$arr,$low,$high)
{
if($low >= $high)
{
return;
}
//标记位
$povion = $arr[$low];
while ($low <$high )
{
while ($low < $high && $arr[$high] <= $povion)
{
$high--;
}
$arr[$low] = $arr[$high];
while ($low < $high && $arr[$low] > $povion)
{
$low++;
}
$arr[$high] = $arr[$low];
}
//循环完了之后将标记位回复到i=j相交的位置
$arr[$low] = $povion;
return $low;
}
function Qsort(&$arr,$low,$high)
{
if($low >= $high )
{
return;
}
while($low < $high)
{
$povision = Partion($arr,$low,$high);
Qsort($arr,$low,$povision-1);
$low = $povision+1;
}
//正常的递归调用快排算法如下
// $povision = Partion($arr,$low,$high);
// Qsort($arr,$low,$povision);
// Qsort($arr,$povision+1,$high);
}
突然发现一个问题,我原来混淆了斐波拉契数列。把n的阶乘当成斐波拉契数列数列啦。斐波拉契数列定义应该是Feb(n) = Feb(n-1)+Feb(n-2);
代码同理:
function Feb($n)
{
if($n<=2)
{
return 1;
}
$res = Feb($n-1)+Feb($n-2);
return $res;
}
$res = Feb(20);
print_r($res);
function Febs($n,$sum1,$sum2)
{
if($n<2)
{
return $sum1;
}
else
{
return Febs($n-1,$sum2,$sum1+$sum2);
}
}
print_r(Febs(20,1,1));
其实所谓尾递归,还是递归调用。但是内部就是用的所谓的迭代。其实可以用while循环来改写。将else部分替换成while的话,可能会更显而易见。