递归方法的理解

news2024/11/26 17:00:39
递归方法调用 :方法自己调用自己的现象就称为递归。
递归的分类 : 直接递归、间接递归。
 直接递归:方法自身调用自己
public void methodA (){
methodA ();
}

间接递归:可以理解为A()方法调用B()方法,B()方法调用C()方法,C()方法调用A()方法。 

public static void A (){
B ();
}
public static void B (){
C ();
}
public static void C (){
A ();
}
说明
递归方法包含了一种 隐式的循环
递归方法会 重复执行 某段代码,但这种重复执行无须循环控制。
递归一定要向 已知方向 递归,否则这种递归就变成了无穷递归,停不下来,类似于 死循环 。最终
发生 栈内存溢出

举例1:计算1 ~ n的和

public class RecursionDemo {
public static void main ( String [] args ) {
RecursionDemo demo = new RecursionDemo ();
// 计算 1~num 的和,使用递归完成
int num = 5 ;
// 调用求和的方法
int sum = demo . getSum ( num );
// 输出结果
System . out . println ( sum );
}
/*
通过递归算法实现 .
参数列表 :int
返回值类型 : int
*/
public int getSum ( int num ) {
/*
num 1 , 方法返回 1,
相当于是方法的出口 ,num 总有是 1 的情况
*/
if ( num == 1 ){
return 1 ;
}
/*
num 不为 1 , 方法返回 num +(num-1) 的累和
递归调用 getSum 方法
*/
return num + getSum ( num - 1 );
}
}

代码执行图解:

代码解释

/*
* 当程序执行时,它会按照以下流程进行:

1. `main` 方法被调用。
2. 一个 `RecursionDemo` 类的对象 `demo` 被创建。
3. `n` 被赋值为 5。
4. 调用 `demo.getSum(n)` 方法,其中 `n` 的值为 5。
5. 进入 `getSum` 方法。
6. `n` 的值不为 1,因此程序执行 `return n + getSum(n - 1);`,其中 `n - 1` 的值为 4。
7. 程序递归调用 `getSum` 方法,将参数值 `4` 传递给它。
8. 再次进入 `getSum` 方法。
9. `n` 的值不为 1,因此程序执行 `return n + getSum(n - 1);`,其中 `n - 1` 的值为 3。
10. 程序递归调用 `getSum` 方法,将参数值 `3` 传递给它。
11. 再次进入 `getSum` 方法。
12. `n` 的值不为 1,因此程序执行 `return n + getSum(n - 1);`,其中 `n - 1` 的值为 2。
13. 程序递归调用 `getSum` 方法,将参数值 `2` 传递给它。
14. 再次进入 `getSum` 方法。
15. `n` 的值不为 1,因此程序执行 `return n + getSum(n - 1);`,其中 `n - 1` 的值为 1。
16. 程序递归调用 `getSum` 方法,将参数值 `1` 传递给它。
17. 再次进入 `getSum` 方法。
18. `n` 的值为 1,因此程序直接返回 1。
19. 回到上一层递归调用,将返回的值 1 加上当前层的 `n` 的值(为 2),得到结果 3,返回给上一层。
20. 继续返回上一层递归调用,将返回的值 3 加上当前层的 `n` 的值(为 3),得到结果 6,返回给上一层。
21. 继续返回上一层递归调用,将返回的值 6 加上当前层的 `n` 的值(为 4),得到结果 10,返回给上一层。
22. 继续返回上一层递归调用,将返回的值 10 加上当前层的 `n` 的值(为 5),得到结果 15,返回给上一层。
23. 回到 `main` 方法,将返回的结果 15 赋值给 `sum` 变量。
24. `System.out.println(sum);` 将结果打印到控制台上。

所以,程序的输出结果为 `15`。
*
*
*
* */
}

举例2:递归方法计算n!

public int multiply ( int num ){
if ( num == 1 ){
return 1 ;
} else {
return num * multiply ( num - 1 );
}
}

 

public int f ( int num ){
if ( num == 0 ){
return 1 ;
} else if ( num == 1 ){
return 4 ;
} else {
return 2 * f ( num - 1 ) + f ( num - 2 );
}
}

举例3:已知有一个数列:f(0) = 1f(1) = 4f(n+2)=2*f(n+1) + f(n),其中n是大于0的整数,求f(10)的值。

public int func ( int num ){
if ( num == 20 ){
return 1 ;
} else if ( num == 21 ){
return 4 ;
} else {
return func ( num + 2 ) - 2 * func ( num + 1 );
}
}

举例4:计算斐波那契数列(Fibonacci)的第n个值

斐波那契数列满足如下规律,
1 , 1 , 2 , 3 , 5 , 8 , 13 , 21 , 34 , 55 ,....
即从第三个数开始,一个数等于前两个数之和。假设 f(n) 代表斐波那契数列的第 n 个值,那么 f(n) 满足:
f(n) = f(n-2) + f(n-1);
// 使用递归的写法
int f ( int n ) { // 计算斐波那契数列第 n 个值是多少
if ( n < 1 ) { // 负数是返回特殊值 1 ,表示不计算负数情况
return 1 ;
}
if ( n == 1 || n == 2 ) {
return 1 ;
}
return f ( n - 2 ) + f ( n - 1 );
}
// 不用递归
int fValue ( int n ) { // 计算斐波那契数列第 n 个值是多少
if ( n < 1 ) { // 负数是返回特殊值 1 ,表示不计算负数情况
return 1 ;
}
if ( n == 1 || n == 2 ) {
return 1 ;
}
// 从第三个数开始, 等于 前两个整数相加
int beforeBefore = 1 ; // 相当于 n=1 时的值
int before = 1 ; // 相当于 n=2 时的值
int current = beforeBefore + before ; // 相当于 n=3 的值
// 再完后
for ( int i = 4 ; i <= n ; i ++ ) {
beforeBefore = before ;
before = current ;
current = beforeBefore + before ;
/* 假设 i=4
beforeBefore = before; // 相当于 n=2 时的值
before = current; // 相当于 n=3 的值
current = beforeBefore + before; // 相当于 n = 4 的值
假设 i=5
beforeBefore = before; // 相当于 n=3 的值
before = current; // 相当于 n = 4 的值
current = beforeBefore + before; // 相当于 n = 5 的值
....
*/
}
return current ;
}

举例5:面试题

宋老师,我今天去百度面试,遇到一个一个双重递归调用的问题,我琢磨了一下,完全不知道为什
么。打断点了,也还是没看懂为什么程序会那样走。您有空可以看一下,求指教。

private int count = 0 ;
public int recursion ( int k ) {
count ++ ;
System . out . println ( "count1:" + count + " k:" + k );
if ( k <= 0 ) {
return 0 ;
}
return recursion ( k - 1 ) + recursion ( k - 2 ); //287
//return recursion(k - 1);//11
//return recursion(k - 1) + recursion(k - 1);//2047
}

剖析:

最后说两句:
1. 递归调用会占用大量的系统堆栈,内存耗用多,在递归调用层次多时速度要比循环 慢的
,所以在使用递归时要慎重。
2. 在要求高性能的情况下尽量避免使用递归,递归调用既花时间又 耗内存 。考虑使用循环迭 代。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1554194.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3.Labview字符串与路径精讲(下) — 字符串及路径的用法汇总

本章讲解labview中的字符串和路径具体实践用例&#xff0c;从前面板字符串属性到后面板字符串函数应用做出详细概述&#xff0c;通过本文的学习希望大家了解到字符串及路径在labview编程中的重要地位。 本系列文章为labview 从基础到强化到精通的学习文章&#xff0c;大家可以随…

【linux】基础IO |文件操作符

需要掌握&#xff1a;操作文件&#xff0c;本质&#xff1a;进程操作文件。进程和文件的关系 向文件中写入&#xff0c;本质上向硬件中写入->用户没有权利直接写入->操作系统是硬件的管理者&#xff0c;我们可以通过操作系统往硬件写入->操作系统必须提供系统调用&…

Linux 学习之路--工具篇--yum

前面介绍了权限有关的内容&#xff0c;这里继续介绍有关Linux里面常用的工具之一yum 目录 一、简单介绍 <1> 源代码安装 <2>rpm 包安装 <3>yum / apt-get(ubuntu) 安装 二、简单使用 <1>安装包介绍 <2> yum 的基本指令 -- install <…

本地部署的stable diffusion 如何更新controlnet?

stable diffusion 未启动状态 点击“版本管理” 点击“扩展” 找到controlnet&#xff0c;点击右边的“更新”按钮 完成&#xff01;

Linux 动静态库的制作,使用和加载

Linux 动静态库的制作,使用和加载 一.前置说明1.mylib.h2.mylib.c3.mymath.h mymath.c4.如何制作库 二.动静态库的制作1.静态库的制作1.制作2.使用一下静态库,验证是否成功打包 2.动态库的制作1.编译.c源文件文件生成.o目标文件2.打包生成动态库3.编写makefile文件,自动化制作动…

Linux系统中安装一些常用的插件备用

Linux系统中安装一些常用的插件备用 1.安装wget yum -y install wget 2.安装vim yum -y install vim-enhanced 3.更换yum源为国内的阿里云源&#xff08;选择&#xff09; 1、备份CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.…

42 ajax 下载文件未配置 responseType blob 导致的文件异常

前言 这是一个最近的关于文件下载碰到的一个问题 主要的情况是, 基于 xhr 发送请求, 获取下载的文件 然后 之后 xhr 这边拿到 字节序列之后, 封装 blob 来进行下载 然后 最开始我们这边没有配置 responseType 为 blob, arraybuffer, 然后 导致下载出来的 文件大小超过了…

许可型DeFi 项目NEOPIN:在合规的框架下推动DeFi的创新

合规化已成 DeFi 的主流方向 过去的几年里&#xff0c;全球金融市场见证了 DeFi 的快速增长。DeFi 通过提供无需中介的交易和借款等金融服务&#xff0c;为用户带来前所未有的便利。然而&#xff0c;其匿名性和去中心化的特性也为监管和安全带来挑战 —— DeFi项目的透明度不足…

机器学习概论—增强学习

机器学习概论—增强学习 强化学习(Reinforcement Learning, RL)或者说是增强学习,是机器学习的一个领域,旨在使智能体通过与环境的交互学习如何做出决策,它是关于在特定情况下采取适当的行动来最大化奖励。它被各种软件和机器用来寻找在特定情况下应采取的最佳行为或路径…

马上蓝桥杯了,干货总结动态规划专题,祝你考场爆杀(基础篇)猫粮规划 接苹果 魔族密码 最大正方形 最大正方形 2 奶牛比赛

目录 猫粮规划 思路&#xff1a; 接苹果 思路&#xff1a; 魔族密码 思路&#xff1a; 最大正方形 思路&#xff1a; 最大正方形 2 思路&#xff1a; 奶牛比赛 ​编辑 思路&#xff1a; 猫粮规划 思路&#xff1a; 每种食物都有两种状态&#xff0c;记忆化d…

以太网/USB 数据采集卡 24位16通道 labview 256K同步采样

XM7016以太网SUB数据采集卡 XM7016是一款以太网/USB高速数据采集卡&#xff0c;具有16通道真差分输入&#xff0c;24位分辨率&#xff0c;单通道最高采样率256ksps. 16通道同步共计4.096Msps、精密前置增益放大、集成IEPE/ICP硬件支持的特点。本产品采用了多个高精度24位ADC单元…

<QT基础(4)>QLabel使用笔记

Label 前面的文章里面把QLabel批量引入ScrollArea作为预览窗口&#xff0c;这篇把图像填充到QLable的PixelMap展示指定图像。 参数设置 设置QLabel的大小格式 QWidget* widget new QWidget; widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); widget->…

31-5 命令执行漏洞 - RCE漏洞利用

环境准备:构建完善的安全渗透测试环境:推荐工具、资源和下载链接_渗透测试靶机下载-CSDN博客 一、打开pikachu靶场 二、远程命令执行利用 正常情况下这一关卡就是个ping命令,我们只能输入个 ip 靶场就就会ping 这ip 但是我们可以用管道符拼接来执行其他命令,详细可以看我…

每日一题 --- 快乐数[力扣][Go]

快乐数 题目&#xff1a;202. 快乐数 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到…

正弦实时数据库(SinRTDB)的使用(5)-历史数据查询

前文已经将正弦实时数据库的使用进行了介绍&#xff0c;需要了解的可以先看下面的博客&#xff1a; 正弦实时数据库(SinRTDB)的安装 正弦实时数据库(SinRTDB)的使用(1)-使用数据发生器写入数据 正弦实时数据库(SinRTDB)的使用(2)-接入OPC DA的数据 正弦实时数据库(SinRTDB)…

全国产数据采集卡定制,24位八通道以太网数据采集卡 labview 100K采样

XM702是一款以太网型高速数据采集卡&#xff0c;具有8通 道真差分输入&#xff0c;24位分辨率&#xff0c;单通道最高采样率100ksps八通 道同步共计800ksps、精密前置增益放大、集成IEPE/ICP硬件 支持的特点。本产品采用了多个高精度24位ADC单元及配合本 公司多年积累开发的前置…

Linux: 检测工具: monit: cpu占用率的一个例子

最近看到monit使用的CPU有时候会突然的增加,通过perf查看,可以看到是下面这个函数调用占用的比较高。 Overhead Comma Shared Object Symbol 29.72% monit [kernel.kallsyms] [k] __d_lookup__d_lookup29.65% d_lookup proc_fill_cache ` proc_readfd_common iterate_dir ksy…

(2024,嵌套标记化,区域编码器,上下文编码器,Transformer-XL,Mamba)xT:大图像中更大上下文的嵌套标记化

xT: Nested Tokenization for Larger Context in Large Images 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 3. 背景 3.1. 长上下文模型作为上下文编码器 3.2. 线性注意机…

2024年妈妈杯数学建模思路B题思路分享

文章目录 1 赛题思路2 比赛日期和时间3 组织机构4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题 5 建模资料 1 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 2 比赛日期和时间 报名截止时间&#xff1a;2024…

如何在 Oracle 中使用 CREATE SEQUENCE 语句

在本文中&#xff0c;我们将讨论 Oracle CREATE SEQUENCE 语句&#xff0c;其主要目的是提供一种可靠的方法来生成唯一且连续的数值&#xff0c;通常用于数据库表中的主键字段。此功能对于维护数据完整性和效率、确保不同记录之间的标识符有序分配尤其重要。从本质上讲&#xf…