Tail recursion principle

When the compiler detects a tail-recursive function call is when it covers the current active record instead of on the stack to create a new one. The compiler can do this, because the recursive call is the last statement of the current period to be carried out active, so when the call returns a stack frame and nothing else to do, so there is no need to save the stack frame. By covering the current stack frame rather than a re-add on top of it, such as the use of stack space it will be greatly reduced, which makes the actual operating efficiency becomes higher.

Examples

To understand tail recursion is how it works, let us once again in the form of recursion to calculate the factorial. First, it can be very easy for us to understand recursion is not tail-recursive Why previously defined. Before memories of computing n Definition:!! N times to calculate the value of each active period (n-1), so that n = n-1 and continue this process until n = 1 so far. This definition is not tail-recursive, since each active period are dependent on the value returned by n by a less active phase of the return value, each call stack frame thus generated will have to save the child until the next call on the stack the return value is determined. Let us now consider the form of tail recursion to define calculate n! Over [1]   Cheng.
This definition also need to accept the second parameter a, in addition to and not much difference. a (initialized to 1) maintain the level of recursion depth. This allows us to avoid the need to return every value multiplied by n. However, in each recursive call, so that a = na and n = n-1. Continue recursively until n = 1, this end condition is satisfied, a case can be returned directly.
Code Example 3-2 shows a C function facttail, it takes an integer n and to calculate the factorial of n tail-recursive form. This function also accepts a parameter a, a initial value 1. facttail use to maintain a level of recursion depth, and in addition it fact very similar. Readers can take note and implement specific functions tail-recursive definition of similarities.
Example 3-2: factorial in the form of a tail-recursive function implemented [1]  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*facttail.c*/
 
#include"facttail.h"
 
/*facttail*/
 
 
int  facttail( int  n,  int  a)
{
 
     /*Compute a factorialina tail - recursive manner.*/
     
     if  (n < 0)
         return  0;    
     else  if  (n == 0)
         return  1;    
     else  if  (n == 1)
         return  a;
     else
         return  facttail(n - 1, n * a);
 
}
Example 3-2 is a function of the tail-recursive, recursive calls as a single statement of facttail is executed last before the function returns. In facttail happened last statement is also a call to facttail, but this is not required. In other words, after the recursive call can also have other statement is executed, but they can only be executed if the recursive call is not executed [1]   。
Tail recursion is extremely important, not tail recursion, stack consumption function is incalculable, we need to save a lot of stacks of intermediate functions. Such as f (n, sum) = f (n-1) + value (n) + sum; saved n function call stack, using tail recursion f (n, sum) = f (n-1, sum + value (n-)); this function only after a reserved stack can be optimized before deleting.
Perhaps in the C language many exceptions, but the programming language is not only the C language , in a functional language in Erlang (also stack language), if you want to maintain a high concurrency features of the language, it is necessary to replace the traditional use of tail recursion recursion.
The original is wrong: reads as follows:
An algorithm for computer programming .
Tail recursion is directed to the traditional recursive algorithm, the traditional recursive algorithm is considered a scourge in many cases. Its reputation mess, it seems forever and inefficient together.
Tail recursion is calculated from the last start, once for each recursive even if the corresponding results, that is, the function call appears at the end of the calling function, because it is the tail, so there is no need to hold any local variables directly invoked the function returns when crossing the caller, the caller is returned to the caller to go.
The following are specific examples:
Linear recursion:
1
2
3
4
5
long  Rescuvie( long  n) {
 
     return  (n == 1) ? 1 : n * Rescuvie(n - 1);
 
}
Tail recursion:
1
2
3
4
5
6
7
8
9
10
11
12
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);
 
}
When n = 5
For linear recursion, he recursive process is as follows:
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
For tail-recursive, recursive he follows:
TailRescuvie(5)
TailRescuvie(5, 1)
TailRescuvie(4, 5)
TailRescuvie(3, 20)
TailRescuvie(2, 60)
TailRescuvie(1, 120)
120
很容易看出, 普通的 线性递归比尾递归更加消耗资源, 在实现上说, 每次重复的过程调用都使得调用链条不断加长. 系统不得不使用栈进行数据保存和恢复.而尾递归就不存在这样的问题, 因为他的状态完全由n和a保存

Guess you like

Origin www.cnblogs.com/schips/p/11013901.html