scala-尾递归
------------------------- by chenkh -----------------------------
随笔记录什么是尾递归,为什么需要尾递归,尾递归show by example。
0,前言
递归通过灵巧的函数定义,告诉计算机做什么。在函数式编程中,随处可见递归思想的运用。一个递归的经典例子:
//递归快排
def quicksort(ls: List[Int]):List[Int] = {
if(ls.isEmpty)
ls
else
quicksort(ls.filter(_ < ls.head)) ::: ls.head :: quicksort(ls.filter(_ > ls.head))
//quicksort(ls.filter(x => x < ls.head)) ::: ls.head :: quicksort(ls.filter(x => x > ls.head))
}
我们以上面代码最后一个快速排序函数为例,使用递归的方式,其代码实现非常的简洁和通俗易懂。递归函数的核心是设计好递归表达式,并且确定算法的边界条件。上面的快速排序中,认为空列表就是排好序的列表,这就是递归的边界条件,这个条件是递归终止的标志。
1,什么是尾递归?
尾递归本质上仍然是一种递归,可以看做是普通递归方法的改进。
尾递归是指递归调用是函数的最后一个语句,而且其结果被直接返回,这是一类特殊的递归调用。由于递归结果总是直接返回, 尾递归比较方便转换为循环 ,因此编译器容易对它进行优化。
2,为什么需要尾递归?
递归算法需要保持调用堆栈,效率较低,如果调用次数较多,会耗尽内存或栈溢出。然而,尾递归可以克服这一缺点。
3,show by factorial
//递归阶乘
def factorial(n: BigInt): BigInt = {
if(n <=1) 1 else n * factorial(n-1)
}
//尾递归阶乘
def factorialTailRecursive(n: BigInt): BigInt = {
def _loop(acc: BigInt, n: BigInt): BigInt = if(n <=1) acc else _loop(acc*n, n-1)
_loop(1, n)
}
/*
我们发现,由于每次递归调用n-1的阶乘时,都有一次额外的乘法计算,这使得堆栈中的数据都需要保留。在新的递归中要分配新的函数栈。
factorial(4)
--------------
4 * factorial(3)
4 * (3 * factorial(2))
4 * (3 * (2 * factorial(1)))
4 * (3 * (2 * 1))
而尾递归在效率上和循环是等价的,该函数中的 _loop 在最后一步,要么返回递归边界条件的值,要么调用递归函数本身。
factorialTailRecursive(4)
--------------------------
_loop(1, 4)
_loop(4, 3)
_loop(12, 2)
_loop(24, 1)
*/
改写成尾递归版本的关键:
尾递归版本最重要的就是找到合适的累加器,该累加器可以保留最后一次递归调用留在堆栈中的数据,积累之前调用的结果,这样堆栈数据就可以被丢弃,当前的函数栈可以被重复利用。
在这个例子中,变量acc就是累加器,每次递归调用都会更新该变量,直到递归边界条件满足时返回该值。
对于尾递归,Scala语言特别增加了一个注释 @tailrec ,该注释可以确保程序员写出的程序是正确的尾递归程序,如果由于疏忽大意,写出的不是一个尾递归程序,则编译器会报告一个编译错误,提醒程序员修改自己的代码。
scala-尾递归的更多相关文章
- Scala尾递归
递归函数应用 首先,我们来对比两个递归方法的求值步骤. 假设有方法gcd,用来计算两个数的最大公约数.下面是欧几里得算法的实现: def gcp(a: Int, b: Int): Int = if ( ...
- 【Scala】尾递归优化
以递归方式思考 递归通过灵巧的函数定义,告诉计算机做什么.在函数式编程中,随处可见递归思想的运用.下面给出几个递归函数的例子: object RecursiveExample extends App{ ...
- Scala Tail Recursion (尾递归)
Scala对尾递归进行了优化,甚至提供了专门的标注告诉编译器需要进行尾递归优化.不过这种优化仅限于严格的尾递归,间接递归等情况,不会被优化. 尾递归的概念 递归,大家都不陌生,一个函数直接或间接的调用 ...
- Scala进阶之路-尾递归优化
Scala进阶之路-尾递归优化 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 递归调用有时候能被转换成循环,这样能节约栈空间.在函数式编程中,这是很重要的,我们通常会使用递归方法来 ...
- Scala 经典的模式匹配和尾递归
Scala 经典的模式匹配和尾递归 package io import java.io.{BufferedWriter, File, FileWriter} import java.text.Simp ...
- Thinking in scala (4)----阶乘与尾递归
code1: object factorial{ def main(args:Array[String])={ println(factorial(args(0).toInt)) } def fact ...
- scala通过尾递归解析提取字段信息
一.背景 获取数据中以“|”作为字段间的分隔符,但个别字段中数据也是以“|”作为分隔符.因此,在字段提取时需要保护数据完整性. 二.实现 1.数据以“|”分隔,可以采用递归方式迭代解析.通过尾递归方式 ...
- scala实战学习-尾递归函数
求 $$ \Sigma\sideset{^b_a}f(x) $$ object sumfunc{ def sum(f: Int => Int)(a: Int)(b:Int): Int = { @ ...
- Scala 的确棒
我的确认为计算机学院应该开一门 Scala 的语言课程. 在这篇文章中,我会讲述为什么我会有这样的想法,在此之前,有几点我想要先声明一下: 本文无意对编程语言进行评比,我要讲述的主体是为什么你应该学习 ...
- Scala HandBook
目录[-] 1. Scala有多cool 1.1. 速度! 1.2. 易用的数据结构 1.3. OOP+FP 1.4. 动态+静态 1.5. DSL 1.6 ...
随机推荐
- sql server远程备份和恢复
sql server远程备份和恢复 SQLSERVER服务实例名称:192.168.0.2需要备份的数据库名称: a备份机器名称(Client端):192.168.0.3备份机用户:zf 密码:123 ...
- Comparable和Comparator实现对象比较
由文生义: 继承Comparable ,表示该类的实例是可以相互比较的; 继承Comparator,表示该类是一个比较器,里面设置了按什么属性比较,list需要按这个比较器里的规则来比较; 使用方法如 ...
- Can't connect to MySQL server on localhost (0)
配置双主的时候,由于一台始终连不上另一台. 于是我使用root账号远程登录查看,填入账户密码点击连接,结果就提示这样的错误. 一开始以为是权限的问题,于是就授与所有权,结果还是报一样的错. 重新创建一 ...
- Building GCC 4.1.2 in CentOS 7 for Maya API development
Following the official guid: http://help.autodesk.com/cloudhelp/2015/ENU/Maya-SDK/files/Setting_up_y ...
- MVC图片验证码
C#类库: public class YZM { public string YZMcode = String.Empty; public byte[] load() { Bitmap bit = , ...
- CGI
CGI的工作原理一般是这么定义的: 客户端web浏览器浏览某个主页后,利用一定的方式提交数据,并通过HTTP协议向Web服务器发出请求,服务器端的HTTP Daemon(守护进程)将描述的主页信息通过 ...
- 带无缝滚动的轮播图(含JS运动框架)
今天学习了一下轮播图的写作,想到前一阵学过的无缝滚动得思想,所以就把轮播与滚动结合了一下.不过我的代码的神逻辑我自己都不敢恭维,在没网没参照的情况下,只能硬着头皮往下写,希望跟大家共勉吧. js运动框 ...
- iis网站发布相关问题
最近在公司的服务器上发布了一个简单的web应用,整个做下来到上线用了将近2天时间,期间出现了各种问题,现在发出来供大家参考: 1.iis上发布后出现访问网站,出现“IIS服务器被配置为不列出此目录的内 ...
- inteview que2
1.spring的缓存,mybatis缓存a.基于注解的方式 三种注解b.mybatis分为一级session和二级缓存mapperc.采用LRU算法(近期最少使用) http://www.iteye ...
- win8提升winform软件的权限
在win8系统中,微软提高了系统盘文件的权限,提高了其他系统操作的权限,因此一些桌面应用程序在运行时会报一些权限错误,比如C盘文件操作权限,或注册表操作无权限等. 我之前开发过一款用笔记本一键架设无线 ...