百度空间 | 百度首页 
 
查看文章
 
尾递归(tail-recursive)
2009-03-17 20:56
尾递归(tail-recursive)
在进行函数调用时,如果函数体中的最后一个语句都是对系统中其他函数的调用,这个函数调用就是
尾递归的。欲说明尾递归,必须说明尾调用(tail-call)。例如下面的函数调用:
1 p()
2 {
3   ...
4   q();
5   ...
6 }
7
8 q()
9 {
10   ...
11   r();
12   s();
13 }
在执行函数p的某个时候,函数q被调用。q中最后去调用s,当s返回的时候,将值返回给q,但是q原封
不动地将该值返回给p。这里q中最后对s的调用就称为尾调用。
在传统的栈机制计算机(stack machine)中,尾调用可以编译成直接跳转到s的代码处,而不用将返回
地址压入栈中,因为s返回的地方就是q要返回的地址。程序执行到这里的时候,栈中的返回地址本来就
是对的。故s的调用结束不需要返回到q中,而是直接返回到p函数体中对q调用的地方就可以了。
如果函数的所有可能执行路径都以尾调用结束,就说明该函数是尾递归的。
这一点是很重要的,尾递归函数可以在循环结构(loop)中被调用而不消耗栈空间。这种函数通常称为
“迭代函数”(iterative function)。
许多函数既可以用迭代风格来编写,也可以用非迭代(递归)风格来编写。例如求阶乘的函数,我们先
来写出它的非迭代递归式:
factorial (0) -> 1;
factorial (N) -> N * factorial(N-1).
在函数体factorial (N)分支中,最后是对一个表达式求值,而不是对一个函数的调用,所以他不是尾
调用,那么该函数自然就不是尾递归了。
现在写出它的迭代式,这里要引入一个辅助函数:
factorial (N) -> factorial_1 (N,1).
factorial_1 (0,X) -> X;
factorial_1 (N,X) -> factorial_1 (N-1,N*X).
显然这是一个尾递归式。
许多非尾递归的函数可以通过引入一个辅助函数,增加一个额外参数(聚集器)的方法改写成尾递归的。
在函数式编程语言中,不单单是为了优化系统执行的目的,有时候函数必须要写成迭代式才能执行。例
如在无限循环结构中,直接递归,不单单是栈区会溢出,而且语义也难以满足。这也许是栈机制计算机
的不足之处。我们知道,在可计算理论中,可计算函数与递归函数是等价的,并且函数式编程在语义上
更加严谨。

类别:玩耍 | 添加到搜藏 | 浏览() | 评论 (0)
 
最近读者:
 
网友评论:
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码: 请点击后输入四位验证码,字母不区分大小写
      

     

©2009 Baidu