使用递归的注意事项和陷阱 | 学习笔记

简介: 快速学习使用递归的注意事项和陷阱

开发者学堂课程【Scala 核心编程 - 进阶使用递归的注意事项和陷阱学习笔记,与课程紧密连接,让用户快速学习知识。

课程地址https://developer.aliyun.com/learning/course/610/detail/9101


使用递归的注意事项和陷阱


使用递归的注意事项

以求斐波拉契为例,来讲递归的注意事项是什么,先看递归求斐波拉契代码应该怎么写,叫 RecursiverFnb ,斐波那契是一个很厉害的人,为了纪念他将它的序列命令为斐波那契数列,学习斐波拉契数列直接写一个函数,写 fnb ,然后写一个(  n :bigint )表示将来会很大,但返回也是Bigint ,如果 n=1或 n=2则返回1,若 else 则fbn ( n-1 )+ fbn ( n-2)。

接下来会出现什么现象呢,当传一个3进去,斐波拉契系数应该是1,1,2 ,3,5,以此类推,如果给一个3,返回一个2,没有问题,速度很快就出来了,再传一个10,速度也会很快55。

我们来研究一下,当我们使用斐波拉契阶层来处理求值时,观察递归的次数是如何增长的。

研究递归求斐波拉契的数的递归次数的增长情况。如现在整一个数,来把这个数传进去,把这个函数拎到里面,传一个全局变量去测试,先在这里面写一个非常大的数,var count =  Bigint ,初始化为0。此时,调用一次加1,调用递归的次数是把它加起来。

如果传3,递归次数可以看出是3,没问题,如果执行四次,调用次数会变成5,也很正常,五次时,会发现次数开始越来越快,当六时,递归次数变成15次,直接20次,递归一共是13529,求10时,递归次数为13529,求11时,只长了一个,调用次数的增长特恐怖,已经两万次了,因为这个地方要思考11过后里面会重复计算,增加了1,就变很多,几乎是从倍数增长,当30次时,会按照一两千万次的次数增长,30时,是160万好,当31时,200多万,当40次时,程序已经跑不起来了,代码会卡。

递归就不能这么用,由此可得出递归的次数呈现指数增长,增长的根本原因在于里面有两次调用。

如果不是有两次调用,而只是一次就不会指数增长。测一下求阶层,它的统计次数的增长只会增加一个,非常有效。求阶乘和这个最大区别在哪里?

假设不用斐波拉契,换用数测试时,降为了20次,若为40,应当为几千万次的调用,而这里50,只调用25次。因此在写递归时,要考虑出现重复计算,此时要考虑优化,优化的原则一般是改递归为迭代或使用其他办法减少递归次数。

package com.atguigu.chapter14

object RecursiveFnb {

def main(args:Array[string]):Unit={

var count =BigInt(0)

//1 1 2 3 5 ?

println(fbn(50)) // 10 -> 13529 11->21891

println("递归的次数是="+ count)

//研究下递归求斐波拉契的数的递归次数的增长情况!

//递归的次数是指数增长.

def fbn(n:BigInt): BigInt = {

count += 1

if(n==1|n==2)1

else fbn(n-1)+fbn(n-2)//重复计算,需要考虑优化->选代

}

}

有一篇文专门讲了对斐波拉契的优化,一共有多种方式,这里面简单了解。

https://blog.csdn.net/dadai/article/details/50209511

第一次直接改迭代,没有用递归,没有用递归了。

下面继续优化,递归调用,但是优化较好。

越到后面越不容易看懂,是迭代加递归结合使用,这里不是讲算法,讲完课程过后会专门讲数据算法,这里涉及到很多优化的方案,有些需要数学功底的。

这里主要强调递归时防止重复计算,如前面求最大值,求反转的写法绝对不会出问题,因为只有一次,求阶乘,速度也会很快,因为次数并不多,如500啊,BigInt可以算出的,它底层用了不是简单的一个数的存放,是字符串进行处理。如改为 n-2 ,就有重复计算,30时就无法计算。

package com.atguigu.chapter14

object RecursiveFactoria {

def main(args: Array[String]): Unit ={

println(factorial(30)) // 1*2*...10 =

}

//求出阶乘

def factorial(n: BigInt): BigInt =

if (n == 0) 1 else factorial(n - 2) * factorial(n - 1)

}

对于这样的问题,有一种学科专门来研究代码,它的执行的效率以及它递归的次数,叫数值分析,就是专门研究算法的程序必学的一门课程,专门研究代码的执行的效率高低,两个代码不用执行,就可通过数字分析来判断效率高低,因为主要是观察调用的次数,能计算出按什么样的规律来增长。

使用递归的注意事项,在开发时要注意,否则代码会出大问题。

相关文章
|
C语言 Windows
C语言实现扫雷(自动排查),递归展开
C语言实现扫雷(自动排查),递归展开
90 0
|
6月前
|
算法 C语言 C++
【新手解答8】深入探索 C 语言:递归与循环的应用
【新手解答8】深入探索 C 语言:递归与循环的应用
83 0
|
6月前
|
机器学习/深度学习 算法 C语言
【新手解答9】深入探索 C 语言:递归与循环的应用2
【新手解答9】深入探索 C 语言:递归与循环的应用2
70 0
|
运维 Shell
【运维知识高级篇】超详细的Shell编程讲解4(for循环+并发问题+while循环+流程控制语句+函数传参+函数变量+函数返回值+反向破解MD5)(二)
【运维知识高级篇】超详细的Shell编程讲解4(for循环+并发问题+while循环+流程控制语句+函数传参+函数变量+函数返回值+反向破解MD5)(二)
117 0
|
运维 Shell 数据安全/隐私保护
【运维知识高级篇】超详细的Shell编程讲解4(for循环+并发问题+while循环+流程控制语句+函数传参+函数变量+函数返回值+反向破解MD5)(一)
【运维知识高级篇】超详细的Shell编程讲解4(for循环+并发问题+while循环+流程控制语句+函数传参+函数变量+函数返回值+反向破解MD5)
179 0
如何使用递归及注意事项
如何使用递归及注意事项
79 0
feof用法重点详解(易被误用判断文件结束!!!)
feof用法重点详解(易被误用判断文件结束!!!)
|
机器学习/深度学习 人工智能 算法
从频度引发的c语言多重for循环乃至编写算法思路的思考
首先需要声明的是,笔者是一名有C语言基础并正在为考研而复习数据结构的大学生,本篇文章中的for循环代码来自于清华大学严蔚敏教授出版的《数据结构》。 本篇博客适用于初学者理解C语言for循环,多重for循环、数据结构频度、线性代数矩阵等知识点。 整篇文章从频度开始,讲述两个矩阵相乘算法,最后讲述整个算法的设计原理
203 4
从频度引发的c语言多重for循环乃至编写算法思路的思考
|
算法 程序员 编译器
【C】掌握函数基本知识+理解函数递归
【C】掌握函数基本知识+理解函数递归
92 0
【C】掌握函数基本知识+理解函数递归
|
Java Scala 开发者
循环的注意事项和练习题|学习笔记
快速学习循环的注意事项和练习题。
循环的注意事项和练习题|学习笔记