快速业务通道

浅谈尾递归的优化方式

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-07-03

在上文《尾递归与Continuation》里,我们谈到了尾递归的概念和示例,不过有些朋友对于尾递归的 功效依然有所怀疑。因此现在,老赵再简单讲解一下尾递归的优化原理,希望能给大家以一定理性认识。

尾递归的循环优化

尾递归,即是递归调用放在方法末尾的递归方式,如经典的阶乘:

int FactorialTailRecursion(int n, int acc)
{
  if (n == 0) return  acc;
  return FactorialTailRecursion(n - 1, acc * n);
}

由于递归在方法的末尾,因此方法中的局部变量已经毫无用处,编译器完全可以将其“复用”,并把 尾递归优化为“循环”方式:

int FactorialLoopOptimized(int n, int acc)
{
  while (true)
   {
    if (n == 0) return acc;

    acc *= n;
    n--;
   }
}

不过,上文还提到了尾递归中的常用技巧Continuation。那么对于如下形式的Continuation,编译器 又该如何优化呢?

int FactorialContinuation(int n, Func<int, int> continuation)
{
   if (n == 0) return continuation(1);
  return FactorialContinuation(n - 1, r  => continuation(n * r));
}

我们先用“人脑”来思考一下,这段代码的执行方式是怎么样的。我们每次使用n和contn 调用FactorialContinuation时,都会构造一个新的contn - 1,并同n - 1传入下一次 FactorialContinuation调用中去。以此类推,直到n等于0时,就直接调用cont0并返回。至 于每个Continuation的定义,我们可以归纳出如下结果:

Func<int, int> contn = r => r * n

因此:

Factorial(n)
  = contn(contn - 1(... (cont2(cont1(cont0(1)))...))
  = n * ((n – 1) *  (...(2 * (1 * 1))...)) = 
  = n * (n - 1) * ... * 2 * 1
  =  n!

于是,我们可以根据这个“意图”,将FactorialContinuation方法“优化”为如下形式:

int FactorialLoopOptimized2(int n, Func<int, int> continuation)
{
  LinkedList<Func<int, int>> contList = new LinkedList<Func<int,  int>>();

  while (true)
  {
    if (n == 0) break;

     int tempN = n;
    Func<int, int> newCont = r => tempN *  r;
    contList.AddFirst(newCont);

    n--;
    continuation =  newCont;
  }

  return contList.Aggregate(1, (acc, cont) => cont (acc));
}

我们构造了一个Continuation函数链表,随着n递减,每次都会把新的Continuation函数插入到链表头 ,最后Aggregate方法会将第一个参数(累加器)依次运用到每个函数中去,得到最后结果并返回。只可 惜,这个优化完全是我们“一厢情愿”而已,这么做的前提是“理解”了函数的意义,把方法的迭代调用 “拆开”,而编译器是无法(还是很难)帮我们优化到如斯地步的。那么编译器对于此类问题又该如何解 决呢?

之前,我们使用C#中的匿名方法特性来构造每个Continuation方法。如果我们使用自定义的封装类, 再将递归“优化”成循环,FactorialContinuation又会成为什么样呢?如下:

private class Continuation
{
  public Continuation(Func<int, int>  cont, int n)
  {
    this.cont = cont;
    this.n = n;
  }

  private Func<int, int> cont;
  private int n;

  public  int Invoke(int r)
  {
    return this

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号