Scala进阶之路-尾递归优化

                                   作者:尹正杰

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

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

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

1>.循环调用

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

2>.递归调用

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

3>.尾递归

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

二.尾递归优化案例展示

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

  我们先以下案例:

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

  以上代码测试结果如下:

2>.尾递归优化

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

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

  测试结果如下:

三.如果编写尾递归函数

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

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

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

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

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

  

转载于:https://www.cnblogs.com/yinzhengjie/p/9370898.html

Scala进阶之路-尾递归优化相关推荐

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

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

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

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

  3. Scala进阶之路-并发编程模型Akka入门篇

    Scala进阶之路-并发编程模型Akka入门篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Akka Actor介绍 1>.Akka介绍 写并发程序很难.程序员不得不处 ...

  4. Python 进阶之路 (九) 再立Flag, 社区最全的itertools深度解析(上)

    前言 大家好,今天想和大家分享一下我的itertools学习体验及心得,itertools是一个Python的自带库,内含多种非常实用的方法,我简单学习了一下,发现可以大大提升工作效率,在sf社区内没 ...

  5. Android程序员的进阶之路

    本文主要论述的是Android程序员的进阶之路,博主本人就是一名android开发攻城狮,所以这里讲述的大多数是android开发攻城狮的技术进阶之路,如有问题请多指正. 大家都知道程序员之中有有菜鸟 ...

  6. YOLO系列算法精讲:从yolov1至yolov4的进阶之路(呕心沥血2万字超全整理,建议收藏!)

    从刚开始接触YOLO到现在也已经有大半年时间了,中间也陆陆续续接触过其它网络.最近又抽时间研究了一下YOLOv4. 因此,趁此机会,将yolov1到yolov4进行一个全面的整理和总结,希望对即将入坑 ...

  7. 前端进阶之路: 前端架构设计(2)-流程核心

    可能很多人和我一样, 首次听到"前端架构"这个词, 第一反应是: "前端还有架构这一说呢?" 在后端开发领域, 系统规划和可扩展性非常关键, 因此架构师备受重视 ...

  8. 运维工程师打怪升级进阶之路 V2.0

    很多读者伙伴们反应总结的很系统.很全面,无论是0基础初学者,还是有基础的入门者,或者是有经验的职场运维工程师们,都反馈此系列文章非常不错! 命名:<运维工程师打怪升级之路> 版本:V1.0 ...

  9. 今天,公司架构师跟我分享多年的私货 | 进阶之路必读书籍(附下载链接)

    HTML与CSS 初级 <Head First HTML与CSS(第2版)>豆瓣评分:9.3 入门经典,初始获得信息的好途径.帮助读者逐步构件小的知识点,再结合一本整体的类别逻辑型的书,就 ...

  10. 获取日志的等级_进阶之路:Java 日志框架全画传(中)

    导读:随着互联网和大数据的蓬勃发展,分布式日志系统以及日志分析系统得到了广泛地应用.目前,几乎在所有应用程序中,都会用到各种各样的日志框架来记录程序的运行信息.鉴于此,工程师十分有必要熟悉主流的日志记 ...

最新文章

  1. 理解Docker(5):Docker 网络
  2. NYOJ-括号配对问题 技巧性的非栈道法
  3. CentOS 7 - 最小化安装后,解决无法使用yum命令问题!!
  4. oracle php
  5. linux主机ftp传输文件效率,FTP和TCP的文件传输效率对比测试分析
  6. python:动态参数*args
  7. Redis 持久化——RDB
  8. python自动输入_使用Python和pywin32自动输入数据
  9. 在字符串中找出第一个只出现一次的字符
  10. 如何在浏览器中增加Jupyter / ipython笔记本的单元格宽度?
  11. 学习之法 —— 如何阅读代码、如何编写代码
  12. tcp压力测试工具_DNS压力测试工具之——DNSperf
  13. MySql cmd下的学习笔记 —— 有关select的操作(order by,limit)
  14. MySQL基础学习特殊篇 入门限定
  15. Dalamud:FFXIV插件框架和API-源码
  16. libtorrent java_关于libtorrent库的安装
  17. RocketMQ存储篇——整体结构以及MappedFile讲解
  18. ubuntu20 yarn报错
  19. 2021宇哥八套卷总结—第三套试卷分析
  20. Learned Image Compression with Discretized Gaussian Mixture Likelihoods and Attention Modules文献复现

热门文章

  1. Android自定义View【实战教程】4⃣️----BitmapShader详解及圆形、圆角、多边形实现
  2. Math源码java_从零开始的Java学习记录(26)——Math类及其些许源码
  3. ble主服务的uuid 是一致的吗_nrf52832 开发之添加DFU服务
  4. 文件怎么更新_iOS屏蔽更新描述文件以及超级详细安装方法分享
  5. php+app接口返回json数据,PHP对接APP的接口类,可返回json数据,xml数据
  6. js添加option设置空值_3.11 在散点图中添加标签(2)
  7. html如何连接外部网页,怎么链接一个外部的css文件?
  8. python常用网站信息收集:持续更新版本--
  9. Windows注销后nginx.exe文件仍能继续运行
  10. python点图为什么显示不出来_matplotlib图只显示点而不是lin