Scala进阶之路-尾递归优化

                                   作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

  递归调用有时候能被转换成循环,这样能节约栈空间。在函数式编程中,这是很重要的,我们通常会使用递归方法来遍历集合。而不是所有的递归都能被优化。递归之所有能被优化是在指在函数的最后一行为递归调用(即尾递归),并且这个递归调用没有其它元素参与。

一.什么情况能导致栈的溢出

1>.循环调用

  答:循环调用并不会导致栈的溢出,因为循环是一个压栈和弹栈的过程。

2>.递归调用

  答:递归调用会导致栈的溢出。因为递归调用一直在压栈,而之前的栈并不会释放资源,这样随着压栈的堆积,栈空间溢出那是迟早的事儿。

3>.尾递归

  答:可以进行优化,将递归转换成循环实现,避免栈的溢出。

二.尾递归优化案例展示

1>尾递归不能有其它参数参与

  我们先以下案例:

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/
package cn.org.yinzhengjie.function object TailRecursion {
//定义递归函数
def sum(args:Seq[Int]):BigInt = {
if(args.isEmpty) {
0
} else{
args.head + sum(args.tail)
}
}
def main(args: Array[String]): Unit = {
sum(1 to 10000)
}
}

  以上代码测试结果如下:

2>.尾递归优化

  我们将上面的代码稍微进行改动,就可以轻松实现尾递归优化啦。具体代码如下:

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/
package cn.org.yinzhengjie.function object TailRecursion {
//定义尾递归函数
def sum(x:Seq[Int] , part :BigInt):BigInt = {
if(x.isEmpty) {
part
} else {
sum( x.tail ,x.head + part)
}
}
def main(args: Array[String]): Unit = {
val res = sum(1 to 1000000000,0)
println(s"res的结尾为:${res}")
}
}

  测试结果如下:

三.如果编写尾递归函数

  所谓的尾递归就是最后一步如果是递归操作本身(即没有和其它参数参与),此时它就是一个尾递归函数,它就变成循环了,因此不会出现栈溢出的情况。能实现尾递归的原理就是当然的栈并不需要从下一个栈中拿数据才能释放。也就是说,当前的栈调用下一个栈时不依赖下一个栈返回数据才能结束,因此当它调用下一个栈时,也就可以让当前的栈执行弹栈操作,当下一个栈执行完毕时,也不需要下下个栈返回数据,因此,下一个栈也可以实现弹栈操作,综上所述,尾递归的就和咱们写的死循环是一个原理啦,就是实现压栈和弹栈的过程,因此始终不会栈溢出的情况哟!

  我们再举一个尾递归的例子如下:

 /*
@author :yinzhengjie
Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/
EMAIL:y1053419035@qq.com
*/
package cn.org.yinzhengjie.function object TailRecursion {
//定义尾递归函数
def sayHello(str:String):Unit= {
println(str)
sayHello(str)
}
def main(args: Array[String]): Unit = {
sayHello("yinzhengjie")
}
}

  以上程序我执行了5分钟,依旧没有出现栈溢出的情况,

  当然如果是你讲上面的尾递归函数的两行代码调换一下,当然依旧还是递归函数,但最后一行不是递归函数本身了,因此不是尾递归函数,很显然会出现栈内存溢出。

  

Scala进阶之路-尾递归优化的更多相关文章

  1. Scala进阶之路-Spark本地模式搭建

    Scala进阶之路-Spark本地模式搭建 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Spark简介 1>.Spark的产生背景 传统式的Hadoop缺点主要有以下两 ...

  2. Scala进阶之路-Scala中的泛型介绍

    Scala进阶之路-Scala中的泛型介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 通俗的讲,比如需要定义一个函数,函数的参数可以接受任意类型.我们不可能一一列举所有的参数类 ...

  3. Scala进阶之路-面向对象编程之类的成员详解

    Scala进阶之路-面向对象编程之类的成员详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Scala中的object对象及apply方法 1>.scala 单例对象 ...

  4. Scala进阶之路-Scala中的枚举用法案例展示

    Scala进阶之路-Scala中的枚举用法案例展示 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Scala中的枚举值和Java中的枚举值有点差别,不过使用起来也都差大同小异,我这 ...

  5. Scala进阶之路-Scala中的高级类型

    Scala进阶之路-Scala中的高级类型 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类型(Type)与类(Class)的区别 在Java里,一直到jdk1.5之前,我们说 ...

  6. Scala进阶之路-Scala中的Ordered--Ordering

    Scala进阶之路-Scala中的Ordered--Ordering 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任.   说道对象的比较,在Java中大家最熟悉不过的就是实现类本身实 ...

  7. Scala进阶之路-反射(reflect)技术详解

    Scala进阶之路-反射(reflect)技术详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Scala中的反射技术和Java反射用法类似,我这里就不一一介绍反射是啥了,如果对 ...

  8. Scala进阶之路-正则表达式案例

    Scala进阶之路-正则表达式案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 废话不多说,正则大家都很清楚,那在Scala如何使用正则了?我们直接上个案例,如下: /* @au ...

  9. Scala进阶之路-进程控制之执行shell脚本

    Scala进阶之路-进程控制之执行shell脚本 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 废话不多说,我这里直接放一个案例. /* @author :yinzhengjie ...

随机推荐

  1. 《Linux内核分析》第八周:进程的切换和系统的一般执行过程

    杨舒雯(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验目的: 使用gdb ...

  2. jiedui

    源代码:https://github.com/hanzhaoyan/jieduizuoye/tree/master 功能要求: 该程序用图形界面实现下面功能:用计算机产生一个100以内的随机数,游戏者 ...

  3. shell脚本--输入与输出

    输出带有转义字符的内容 单独一个echo表示一个换行 使用echo输出时,每一条命令之后,都默认加一个换行:要想取消默认的换行,需要加 -n 参数. #!/bin/bash #文件名:test.sh ...

  4. Install Jetty web server on CentOS 7 / RHEL 7

    http://www.eclipse.org/jetty/download.html http://www.eclipse.org/jetty/documentation/current/startu ...

  5. Oracle11.2.0.1 升级Oracle11.2.0.4 后 listener 的端口改变需要处理

    1. 因为Oracle采取了异地升级 发现 Oracle的端口号发生了变化: 2. 如果之前的连接还需要用的话 需要禁用 dbhome1 里面的监听 只打开dbhome2的监听 并且修改 监听的端口号 ...

  6. [同事转帖] .net core的服务器模式和工作站模式

    发现自己的服务器上面的进程占用越来越厉害 所以就跟同事讨论了一下 性能组同事 说已经发现 并且给了一个 网址 这里转帖记录一下 避免以后找不到. .NET Core是一个开源通用的开发框架,具有跨平台 ...

  7. centos7改中文

    centos7的与centos6有少许不同: 1.安装中文包: root@iZj6cbstl2n6r280a27eppZ tmp]# yum groupinstall "fonts" ...

  8. scipy线性模块liner(linalg)

    #liner import numpy as np from scipy import linalg as lg arr=np.array([[1,1],[0,1]]) matr=np.mat('[1 ...

  9. (一) 关于配置travis-ci持续集成python pytest测试的相关记录

    首先由于公司用上了高大上的travis-ci商用版,一直想试着学学弄弄看.现在要写openapi的相关测试,而且要在travis-ci上集成.我就想体验一下这个过程.所以自己弄了一个public的仓库 ...

  10. ADOTable的CancelUpdate和CancelBatch的区别?(100分)

    出差新疆,修改别人的代码,请教CancelUpdate和CancelBatch的区别! 如果希望取消对当前记录所做的任何更改或者放弃新添加的记录,则必须调用CancelUpdate 方法CancelB ...