函数递归调用的机制|学习笔记

简介: 快速学习函数递归调用的机制。

开发者学堂课程【Scala 核心编程-基础函数递归调用的机制】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/609/detail/8931


函数递归调用的机制

 

内容介绍

一、递归调用快速入门

二、总结

 

一、递归调用快速入门

这节课讲解递归,函数中递归使用比较多,而且马丁也推荐使用递归,递归即一个函数在函数体内又调用了本身,则称为递归调用。

1、当调用 test(4)

观察如下代码:

deftest (n: Int) {

if(n>2) {

test(n- 1)

}

printin("n="+n) //

}

如上这个代码写了一个函数接收 n,如果 n<2,进行计算 test(n-1),打印 print,那么当调用 test(4)print 应该输出什么?下面进行递归代码的分析,如图:

image.png

根据之前讲解的原则,一旦有一个函数就会开辟一个新的栈空间,所以内存中会开辟一个main栈,栈中调用test(4),还会开辟一个 test 空间,会接收到 n=4,然后再代码中执行判断 n>2是否成立,显然4>2成立,所以 test 栈会执行test 中的代码,进行调用 test(n-1),就是调用 test(3),而 print 不会进行输出,因为紧接着又会开辟一个 test(3)空间,此时 n=3,然后逻辑继续执行,判断3>2,然后继续执行后得到 test(2),print 仍然待执行,而 test(2)为一个函数,所以再次开辟 test(2)栈空间,此时 n=2,而判断条件 n>2则不再成立,于是执行 print 输出 n,显然会输出 n=2。
此时栈顶到了 test(2),等到 test(2)执行完毕栈顶就回到了 test(3),进行执行 test(3)的 print,这时打印的 n 为test(3)中的 n,为 n=3,执行完毕后再往下执行 test(4)中的 print,打印 n=4,然后回到 main 栈执行,而 main 主栈一旦执行完毕整个栈就全部销毁。所以最后输出为2,3,4,然后运行代码进行验证,如下:

package com. atguigu. chapter05. recursive

object Demo01 {

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

test(4)

def test (n: Int) {

if(n>2){

test (n - 1)

}

println("n=" + n) //

}}

运行结果如下:

D: \program\jdk8 \bin \java

n=2

n=3

n=4

说明分析正确。

2、当调用 test2(4)

那么如下代码,如果调用 test2(4)也输入值为4的话,最后输出结果是什么?

def test2 (n: Int) {

if(n>2){

test2 (n - 1)

}else {

println("n=" + n)

}

此时只能输出一个结果,因为这个结果是 else,else 只有在 test(2)时有机会进入栈,然后执行 print,而没有其他机会进行输出。代码运行如下:

package com. atguigu. chapter05. recursive

object Demo01 {

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

test2(4)

def test (n: Int) {

if(n>2){

test (n - 1)

}

println("n=" + n) //

}

def test2 (n: Int) {

if(n>2){

test2 (n - 1)

}else {

println("n=" + n)

}

}}

运行结果如下:

D: \program\jdk8 \bin \java

n=2

说明分析验证成功。

递归是后面学习大数据常用到的一种写法,一定要学懂。

 

二、总结

根据上面学习的函数递归调用总结需要遵守的重要原则如下 :

1、当程序执行一个函数时,就创建个新的受保护的独立空间(新函数栈)。比如在上面案例中一旦调用了 test就会开辟一个新的空间,而这个空间是属于栈的但又是独立的。

2函数的局部变量是独立的,不会相互影响。在将来做开发时可能面对传入的值不是基本值类型,而是引用类型,就可能会出现有一个堆,比如在主栈中创建了一个对象 obj,但 obj 的数据并不在 main 栈中,而是在堆当中,所以obj 因为种种原因就指到了堆当中,而如果把 obj 传给 test(3)栈,test(3)栈则也有可能执行堆,甚至在堆当中还可以存入一个栈,就像 struts2拦截器实现的底层机制就是把一个对象放到栈中,然后不停的开栈,每一个栈都有机会去修改这个对象。在以前讲 java 的数据结构时讲解过迷宫回溯,递归中有很多递归,在堆当中有很多老鼠在找迷宫,那个老鼠先找到就发一个信号,然后全部进行退出,其实这个也能实现这种堆栈的效果。如图:

image.png

所以如上函数的局部变量是独立的,不会相互影响的,如果受到影响则是引用类型。

3递归必须向退出递归的条件逼近,否则就是无限递归。比如上面讲的代码,只有 test(n-1)才会出现 n 不再大于2,才能进行退出,如果改为 test(n+1)然后进行运行,如:

if(n>2){

test (n + 1)

}

运行结果如下:

D: \program\jdk8\bin\java

Exception in thread "main" java.lang . Stac koverflowError

at com. atguigu. chapter05. recursive . Demo01$. test (Demo01.scala:9)

at com. atguigu. chaptero5. recursive . Demo01$. test (Demoo1.scala:9)

……

运行结果提示出现栈溢出,并且不停的进行输出。栈内存就会不停的往上走开辟栈空间,导致死归,如图:

image.png

所以写递归时特别重要的东西就是如何去判断退出递归的条件,像二分查找中也有递归。

4当一个函数执行完毕,或者遇到 return 就会返回,遵守谁调用,就将结果返回给谁的机制。比如上面讲的案例,在 test(4)执行完毕后,遵循谁调用就返回给谁的机制,所以将结果返回给 test(3)

相关文章
|
弹性计算 Kubernetes Cloud Native
云原生架构下的微服务设计原则与实践####
本文深入探讨了在云原生环境中,微服务架构的设计原则、关键技术及实践案例。通过剖析传统单体架构面临的挑战,引出微服务作为解决方案的优势,并详细阐述了微服务设计的几大核心原则:单一职责、独立部署、弹性伸缩和服务自治。文章还介绍了容器化技术、Kubernetes等云原生工具如何助力微服务的高效实施,并通过一个实际项目案例,展示了从服务拆分到持续集成/持续部署(CI/CD)流程的完整实现路径,为读者提供了宝贵的实践经验和启发。 ####
|
Kubernetes 测试技术 持续交付
C# 一分钟浅谈:集成测试与系统测试
【10月更文挑战第19天】本文详细介绍了集成测试和系统测试的概念、目的及其在软件开发中的重要性。通过分析常见问题和易错点,结合代码示例,探讨了如何通过代码规范、自动化测试和持续集成等方法提高测试效果,确保软件质量和可靠性。
652 1
|
JavaScript 安全 数据安全/隐私保护
去哪儿旅行JS逆向:__m__加密和请求头键值对加密(上篇)
去哪儿旅行JS逆向:__m__加密和请求头键值对加密(上篇)
334 0
去哪儿旅行JS逆向:__m__加密和请求头键值对加密(上篇)
|
机器学习/深度学习 算法 数据挖掘
survey和surveyCV:如何用R语言进行复杂抽样设计、权重计算和10折交叉验证?
survey和surveyCV:如何用R语言进行复杂抽样设计、权重计算和10折交叉验证?
900 1
|
消息中间件 C# RocketMQ
MQ产品使用合集之设置rocketmq的timerMaxDelaySec时间出现报错如何解决
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
912 4
|
Ubuntu Linux 人机交互
快速实现摄像头视频画面的远程预览
通过阿里云生活物联网平台的智能视频服务Link Visual来快速的搭建并实现摄像头视频画面的远程预览功能。
510 21
|
JavaScript 小程序
JS控制input输入特殊字符
JS控制input输入特殊字符
227 0
|
API C#
HandyControl新手引导
HandyControl新手引导
617 0
HandyControl新手引导
|
运维 安全 Linux
如何通过内网穿透实现无公网IP也能远程访问内网的宝塔面板
如何通过内网穿透实现无公网IP也能远程访问内网的宝塔面板
1141 0