首页 > 编程知识 正文

尾递归和普通递归,java递归算法经典实例

时间:2023-05-04 00:17:48 阅读:153349 作者:971

要说末尾递归,需要理解末尾调用

末尾调用定义

所谓维基百科的末尾调用,是指函数内最后的动作返回函数的调用结果的情况,在最后的步骤中新调用的返回值直接反映在当前函数的返回值中

在代码形式上

一个函数最后调用另一个函数

//只是举例,没有使用特定语言的语法

函数f (x ) {

a(x );

b(x );

返回(x; //在函数执行的末尾调用另一个函数

}

理解核心

就是看一个函数调用另一个函数时,它本身是否会“释放”

确定:以下呼叫的末尾呼叫

//情况1

是函数f (x )

{

inta=g(x;

return a;

}

//情况2

是函数f (x )

{

return3g(x;

}

//情况3

是函数f (x )

{

是if(x0 )

{

返回(x;

}

returnr(x;

}

答案

情况1在调用函数g(x )后有其他操作,因此不属于末尾调用。 即使意思相同,但a要得到结果,就需要等待g ) x )函数,所以f ) x )是不能释放的。

情况2不属于尾部调用,因为在调用之后还有另一个操作。 即使写在同一行,也同样不能释放f(x )。

在事例3中,无论x取什么样的值,最后的操作都是函数调用,所以属于末尾调用。

呼叫尾有什么好处

首先请看普通呼叫的过程

//用以下三个函数举例

是函数f (x )

{

RES=g(x;

返回结果1;

}

是函数g (x )

{

RES=r(x;

返回结果1;

}

函数r (x )表示

{

res=x 1;

返回结果1;

}

文本说明

函数调用

调用f(x )在内存中创建调用记录。 也称为调用帧(call frame ),用于保存调用位置和内部变量等信息。

在函数f(x )内调用函数g ) x )时,会在f ) x )的调用框上方形成g ) x )的调用框

在函数g(x )内部还调用函数r ) x ),因此在g ) x )的调用框的上方形成r ) x )的调用框

函数r(x )的调用结束,结果返回g ) x ),同时函数r ) x )结束,“消失”

同样,g(x )呼叫结束,“消失”

最后到f(x ),结束后消失(图中未出现) )。

在上述调用过程中,所有调用帧都位于一个调用堆栈中

以上步骤维基百科中的说明在程序运行时,计算机会为APP应用程序分配一定的内存空间APP应用程序会自行分配获取的内存空间。 其中一部分用于记录程序中调用的每个函数的执行情况。 这就是函数的调用堆栈。 在常规函数调用中,新的堆栈帧(也称为stack frame、“堆栈帧”或简称为“帧”)始终添加到调用堆栈的顶层。 此过程称为“堆栈入”或“堆栈”,意味着将新帧推到堆栈的顶层。

上述呼叫过程中有什么风险

如下图所示,函数调用级数过多时,调用栈会消耗大量内存,甚至会导致内存空间爆炸(栈溢出),导致程序严重卡顿或意外崩溃。

尾部呼叫解决了上述风险

//这是末尾调用

function f () }

m=1;

n=2;

返回(Mn );

}

f (;

与//相同

function f () }

返回(3;

}

f (;

与//相同

g(3);

上面的代码在我们调用g后,发现函数f与f没有任何关系,而是结束了。 因此,如果执行到最后一个步骤,就可以完全删除f () )的调用记录,只保留g ) )的调用记录。

末尾调用的含义

如果所有函数都是尾部调用,则每次执行都会有一个调用帧,从而大大节省内存

什么是末尾递归

末尾递归=末尾调用递归

递归:函数调用本身称为递归

末尾调用:函数最后调用另一个函数

因此,末尾递归可以概括为一个函数在其内部的最后一步调用自己

用python举例

定义记录(x,running_total=0) :

if x==0:

return running_total

else:

#tailrecsum函数的最后一步是调用另一个函数。 其中,这个“另一个函数”本身

returntailrecsum(x-1,running_total x ) ) ) ) ) )。

参考

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。