Before we start to research tail recursion, let’s first have a look at the normal recursion.
A simple factorial implementation by recursion:
function factorial(n){
if(n ===1) {
return 1;
}
return n *factorial(n -1);
}
Let N = 5, see how new stack frame is created for each time of recursive call:
We have two stack frames now, one stores the context when n = 5, and the topmost one for current calculation: n = 4
Now since n equals to 1, we stop recursion. The current stack frame ( n = 1 ) will be poped up, the frame under it will be activated and become the topmost frame, with calculated result 1 passed into.
key note for normal recursion: during recursion, every generated stack frame is needed and could not e destroyed until the final result is calculated. The calculation is actually not started until the recursion reaches the end ( the condition n === 1 fulfills ). If N is a big integer, it will lead to huge number of stack frames and finally the “stack overflow” or “out of memory” is inevitable.
tail recursion
Source code below:
function tailFactorial(n, total) {
if(n ===1)
return total;
return tailFactorial(n -1, n * total);
}
function factorial2(n) {
return tailFactorial(n,1);
}
There are two biggest differences compared with normal recursion:
(1) A new internal function tailFactorial is introduced here.
(2) The calculation is actually now spread within every recursive stack frame. Each frame finishes one part of calculation and pass the current result to the next frame. Once the current stack frame finishes its task, it is actually not needed any more. And thus for example the model browser can then do some optimization on those useless stack frames.
Observe the stack frame for tail recursion step by step:
stack popped up:
When N = 20, the tail recursion has a far better performance than the normal recursion:
Update 2016-01-11
Tail recursion implementation via Scala:
The interesting thing is, after the Scala code is compiled into Java Byte code, compiler will eliminate the recursion automatically:
Tail Recursion in ABAP
First this is the normal recursion:
REPORT zrecursion.
START-OF-SELECTION.
DATA: lv_result TYPE int4.
PERFORM fac USING 6 CHANGING lv_result.
WRITE: / lv_result.
FORM fac USING iv_n TYPE int4 CHANGING cv_result TYPE int4.
DATA: lv_n TYPE i.
cv_result = lv_n = iv_n.
lv_n = lv_n - 1.
IF lv_n > 1.
PERFORM fac USING lv_n CHANGING cv_result.
ENDIF.
IF lv_n = 1.
cv_result = cv_result * lv_n.
ELSE.
cv_result = cv_result * iv_n.
ENDIF.
ENDFORM.
And here comes tail recursion version:
REPORT ztail.
START-OF-SELECTION.
DATA: lv_result TYPE int4.
PERFORM fac USING 5 1 CHANGING lv_result.
WRITE: / lv_result.
FORM fac USING iv_n TYPE int4 iv_acc TYPE int4 CHANGING cv_result TYPE int4.
DATA: lv_n TYPE i,
lv_accumulate TYPE i.
IF iv_n < 1.
cv_result = 1.
ELSEIF iv_n = 1.
cv_result = iv_acc * iv_n.
ELSEIF iv_n > 1.
lv_n = iv_n - 1.
lv_accumulate = iv_acc * iv_n.
PERFORM fac USING lv_n lv_accumulate CHANGING cv_result.
ENDIF.
ENDFORM.
要获取更多Jerry的原创文章,请关注公众号"汪子熙":
相关推荐
### ABAP简单递归算法解析 #### 一、引言 ABAP(Advanced Business ...通过上述分析,我们不仅了解了递归算法的工作机制,也熟悉了ABAP中递归函数的实现方法,这对于进一步学习和应用ABAP编程具有重要意义。
在编程领域,递归是一种强大的工具,...总之,Java中的递归实现阶乘是一个经典的示例,它展示了递归在解决数学问题时的威力和优雅。通过理解和实践这个例子,你可以更好地掌握递归的概念,并将其应用于更复杂的问题中。
c++ 递归 阶乘 n!c++ 递归 阶乘 n!c++ 递归 阶乘 n!c++ 递归 阶乘 n!c++ 递归 阶乘 n!c++ 递归 阶乘 n!c++ 递归 阶乘 n!c++ 递归 阶乘 n!c++ 递归 阶乘 n!c++ 递归 阶乘 n!c++ 递归 阶乘 n!c++ 递归 阶乘...
### 递归法写阶乘 #### 知识点概览 1. **递归的基本概念** ...通过以上分析,我们可以看到递归方法在实现阶乘等数学问题时的优势与局限性。理解递归不仅有助于编写简洁高效的代码,还能加深对算法和数据结构的理解。
在编程领域,递归是一种强大的工具,用于解决复杂问题,特别是处理树形结构或分而治之的问题。...在这个例子中,由于阶乘的性质,我们知道每次递归都将n减1,最终会到达n=1的情况,因此不会出现无限递归。
在这个场景中,我们讨论的是使用易语言实现的递归算法来计算阶乘。 阶乘是一个数学概念,表示一个正整数n的所有小于等于n的正整数的乘积,通常表示为n!。例如,5!(5的阶乘)等于5×4×3×2×1=120。递归算法求阶乘...
/*int f(int n,int a1,int a2) { if(n) return a1; else return f(n - 1, a2, a1 + a2); }*/
2. **效率**:虽然递归在理解和实现上很有吸引力,但它的效率通常不如迭代方法,因为每次递归调用都会增加系统栈的负担。 3. **空间复杂度**:递归可能导致大量的函数调用,消耗内存,特别是在处理大数据时。 在...
在编程领域,递归是一种强大的算法,它通过函数或过程调用自身来解决问题。VB(Visual Basic)作为经典的面向对象编程语言,同样支持...通过学习和实践这个例子,你可以进一步提升自己在VB中的编程能力和对递归的理解。
在Java程序中,有两种常见的方法实现阶乘的计算:递归方式和循环方式。首先,让我们详细解析这两个方法: 1. 递归方式: `getDigui` 方法就是一个递归实现的例子。递归的核心思想是将大问题分解成小问题来解决。在...
在"DLC1_Sample"这个压缩包中,可能包含了演示如何在实际应用中结合树控件和递归计算阶乘的代码示例。通过研究这些示例,初学者可以加深对这两个概念的理解,并提高编程技能。 总之,.NET初学者在学习过程中应掌握...
在求解阶乘和的问题中,递归可以非常有用。阶乘是一个数学概念,表示为n!,n是一个非负整数,n的阶乘定义为所有小于等于n,大于0的正整数的乘积。例如,5! = 5 * 4 * 3 * 2 * 1 = 120。要求阶乘和,我们可以将问题...
本文介绍了如何使用C语言实现阶乘的递归计算,并通过一个简单的用户交互界面支持用户连续输入多个整数并计算其阶乘。这种方法不仅展示了递归技术的应用,同时也提高了用户的体验,使得程序更加实用和友好。对于初学...
在这个示例中,我们使用 lambda 表达式来实现尾递归的阶乘计算。我们使用一个 `factorial` 变量来保存上一轮递归的结果,这样就可以避免栈溢出的问题。 总结 在本篇文章中,我们介绍了 Java8 使用 lambda 实现 ...
c++递归函数的使用,介绍了使用递归实现数组遍历和阶乘函数的函数
java中使用递归方法计算阶乘的代码示例
python javascript C语言 三种递归求阶乘和
C通过运行时堆栈支持递归函数的实现。递归函数就是直接或间接调用自身的函数。 许多教科书都把计算机阶乘和菲波那契数列用来说明递归,非常不幸我们可爱的著名的老潭老师的《C语言程序设计》一书中就是从阶乘的计算...
在编程领域,递归是一种强大的算法,它通过函数或子程序自身调用来解决问题。本示例聚焦于使用C语言实现递归法来计算一个整数N的阶乘(Factorial)。阶乘是一个数学概念,表示从1乘到指定正整数n的所有自然数的积,...
C语言练习程序,采用递归方法求阶乘.调用子函数实现