Scala之尾递归

Scala之尾递归

  
不久前突然看到有人发帖问尾递归,感觉非常奇怪,这东西怎么从来没听说过呢?最近学到Scala才明白为什么需要尾递归。尾递归这东西挺有意思的,由于FP的immutability的特性,使得不可以使用循环,因为循环会改变变量的值,和FP的理念冲突。而如果不用循环就只能使用递归了。可是递归平时都是大家尽量避免的,因为很容易造成stackoverflow,因此就需要尾递归了。而尾递归的的本质其实还是循环,因此编译器最终把尾递归优化成循环来执行了。看到了没有,实际上尾递归解决的问题就是immutable的recursion,很简单吧?

在把递归转换成尾递归中,有一个道理非常重要。递归是表达问题的一个方式,而循环是寻找解决问题的一个方式。尾递归的本质是循环而不是递归。因此在转换的过程中,不要把思路拘泥于递归上,而应该扩展到循环上。理论上来讲,任何递归都可以转换成循环,因为尾递归的本质是循环,因此任何递归也应该都可以转换为尾递归。这是我的理解,因此又回顾那个帖子,当时大家认为不是所有的递归都可以转换成尾递归,这和我的理解相违背,因此我就尝试把一些大家认为无法转换的问题重新用尾递归的方式来诠释了。下面是我的代码。因为初学,一定不是最佳,大家见笑了。

1. Get binary tree height
-------------------------------------------------------------------------------

def getHeight(root:TreeNode):Int={

   recursion(0,List(root))

}


def recursion(layer:Int,list:List[TreeNode]):Int= list match{

    caseNil=> layer

    case _=> recursion(layer+1, process(list))

}


defprocess(list:List[TreeNode]):List[TreeNode]={

    varnewlist:List[TreeNode]=Nil

   for(node<-list){

       if(!node.left.isEmpty)newlist=node.left.get::newlist

       if(!node.right.isEmpty)newlist=node.right.get::newlist

    }

    newlist

}


2.
int C(int m, int n)
{
    if ((n == 0)|| (n == m))
       return 1;
   else
       return C(m - 1, n) + C(m - 1, n - 1);
}
-------------------------------------------------------------------------------

def C(m:Int, n:Int):Int={

    recursion(m, 0,None)(n)

}


def recursion(m:Int, i:Int,arr:Option[Array[Int]]):Array[Int]= i match{

    case _if i==m+1 => arr.get

    case 0=> recursion(m, 1, Option(Array[Int](0)))

    case _=> val ret=process(i,arr.get);recursion(m, i+1, Option(ret))

}


def process(i:Int,arr:Array[Int]):Array[Int]={

    valar=new Array[Int](i+1)

    ar(0)=1

    ar(i)=1


    1 until iforeach(j=>ar(j)=arr(j)+arr(j-1))

    ar

}


3.
public static double H(double val, int n)
{
    if (n ==0)
       return val;
   else
   {
       double left = V(val - 1, n - 1);
       double right = V(val + 1, n - 1);
       return Math.Sqrt(Math.Abs(left * right));
   }
}

public static double V(double val, int n)
{
    if (n ==0)
       return val;
   else 
   {
       double up = H(val * 2, n - 1);
       double down = H(val / 2, n - 1);
       return Math.Sqrt(Math.Abs(up + down));
   }
}
---------------------------------------------------------------------------------------

def H(value:Double,n:Int):Double={

   H_helper(Array(value),n)(0)

}


def V(value:Double,n:Int):Double={

   V_helper(Array(value),n)(0)

}


def H_helper(arr:Array[Double],n:Int):Array[Double]=n match{

    case 0=> caclV(arr)

    case _=> {

       val ar=newArray[Double](arr.length*2)

       for(i<-0 until arr.length) {

          ar(2*i)=arr(i)-1

          ar(2*i+1)=arr(i)+1

       }

       V_helper(ar, n-1)

    }

}


def V_helper(arr:Array[Double],n:Int):Array[Double]=n match{

    case 0=> caclH(arr)

    case _=>{

       val ar=newArray[Double](arr.length*2)

       for(i<-0 until arr.length){

          ar(2*i)=arr(i)*2

          ar(2*i+1)=arr(i)/2

       }

       H_helper(ar, n-1)

    }

}


defcaclH(arr:Array[Double]):Array[Double]={

   if(arr.length==1) return arr

    valar=new Array[Double](arr.length/2)

   for(i<- 0 untilar.length){

       ar(i)=math.sqrt((arr(2*i)*arr(2*i+1)).abs)

    }

    caclV(ar)

}


defcaclV(arr:Array[Double]):Array[Double]={

   if(arr.length==1) return arr

    valar=new Array[Double](arr.length/2)

   for(i<- 0 untilar.length){

       ar(i)=math.sqrt((arr(2*i)+arr(2*i+1)).abs)

    }

    caclH(ar)

}


注意第三题Scala不支持对这种尾递归的优化,因此需要用到TailCalls才行。我用了一下还是挺容易用的。


转载地址:blog.sina.com.cn/s/blog_b9285de20101i5s1.html


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值