Scala进阶之路-尾递归优化
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进阶之路-尾递归优化的更多相关文章
- Scala进阶之路-Spark本地模式搭建
Scala进阶之路-Spark本地模式搭建 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Spark简介 1>.Spark的产生背景 传统式的Hadoop缺点主要有以下两 ...
- Scala进阶之路-Scala中的泛型介绍
Scala进阶之路-Scala中的泛型介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 通俗的讲,比如需要定义一个函数,函数的参数可以接受任意类型.我们不可能一一列举所有的参数类 ...
- Scala进阶之路-面向对象编程之类的成员详解
Scala进阶之路-面向对象编程之类的成员详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Scala中的object对象及apply方法 1>.scala 单例对象 ...
- Scala进阶之路-Scala中的枚举用法案例展示
Scala进阶之路-Scala中的枚举用法案例展示 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Scala中的枚举值和Java中的枚举值有点差别,不过使用起来也都差大同小异,我这 ...
- Scala进阶之路-Scala中的高级类型
Scala进阶之路-Scala中的高级类型 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类型(Type)与类(Class)的区别 在Java里,一直到jdk1.5之前,我们说 ...
- Scala进阶之路-Scala中的Ordered--Ordering
Scala进阶之路-Scala中的Ordered--Ordering 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 说道对象的比较,在Java中大家最熟悉不过的就是实现类本身实 ...
- Scala进阶之路-反射(reflect)技术详解
Scala进阶之路-反射(reflect)技术详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Scala中的反射技术和Java反射用法类似,我这里就不一一介绍反射是啥了,如果对 ...
- Scala进阶之路-正则表达式案例
Scala进阶之路-正则表达式案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 废话不多说,正则大家都很清楚,那在Scala如何使用正则了?我们直接上个案例,如下: /* @au ...
- Scala进阶之路-进程控制之执行shell脚本
Scala进阶之路-进程控制之执行shell脚本 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 废话不多说,我这里直接放一个案例. /* @author :yinzhengjie ...
随机推荐
- js/jquery禁止页面回退
$(function() { //防止页面后退 history.pushState(null, null, document.URL); window.addEventListener('popsta ...
- Cron Expression的用途
对于一些MIS系统,DeadLine,需要用户自己制定事件规则,Cron Expression应该可以派上用场. Cron Maker: http://www.cronmaker.com/
- Chrome 启动参数列表
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --type=gpu-process --channel ...
- FICO基础知识(四)
What is the organizational structure for CO? Operating Concern 经营组织 Controlling Area 成本控制范围 Profit c ...
- CentOS 安全优化
1.操作系统和数据库系统管理用户身份鉴别信息令应有复杂度要求并定期更换. 配置# vi /etc/login.defs 系统默认配置: PASS_MIN_LEN=5 #密码最小长度 PASS_MAX_ ...
- jvm学习三:自定义ClassLoader
第一节我们说过一句话:所有的Java虚拟机实现必须在每个类或接口被Java程序“ 首次主动使用”时才初始化他们 但类加载器却不是这样:类加载器不需要等到某个类“被首次主动使用”时才加载类 两句话的区别 ...
- 关于RabbitMQ Queue Argument的简介
1.Message TTL message在队列queue中可以存活多长时间,以毫秒为单位:发布的消息在queue时间超过了你设定的时间就会被删除掉. channel.queueDeclare(&qu ...
- mangTomany 自关联之个人感悟
介绍: 应用场景:评论表 manyTomany 原则上就是一个类 自己建立一个关系表 这个关系表的列 由自己定义 例如 图中 from_userinfo_id() 是人为规定的 男生列 to_use ...
- 51nod蜥蜴与地下室(1498)(暴力搜索)
题意:一个数组s,再给你a,b值,除了s1和sn外,你可以攻击其他元素,你对这个元素的伤害为a,那么他两边的元素会受到b的牵连伤害,si-a,si-1-b,si+1-b: 求最小的次数,使得这个数组的 ...
- hdu 5126 stars (四维偏序,离线,CDQ套CDQ套树状数组)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5126 思路:支持离线,那么我们可以用两次CDQ分治使四维降为二维,降成二维后排个序用树状数组维护下就好 ...