news 2026/4/17 5:53:55

对递归的两层含义理解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
对递归的两层含义理解

例子1

/**

* 求整数 n 的阶乘

*

* @param n 整数

* @return n 的阶乘

*/

public int factorial(int n) {

if (n == 1) {

return 1;

}

return n * factorial(n - 1);

}

image

Definition

递归是一个循环结构,主要用来处理需要循环执行的任务,和For循环类似的代码结构。

简单说就是函数自己能调用自己。

fun factorial(n:Int):Int{

if(n <= 1) return n

else return n*factorial(n-1)

}

先了解一下内存结构,但这个不是必须的。

image

用图理解:

image

image

从堆栈的角度理解递归

递归的底层就是利用堆栈和指令结构所实现的功能。

image

缺点

从使用堆栈的资源角度来说,会比For以及其他循环结构更耗资源。

内存开销

堆栈:每次函数调用都会在栈上分配新的栈帧,包含参数、返回地址、局部变量等

循环:只在当前栈帧内重复执行,不需要额外的栈空间

上下文切换成本

堆栈(递归):涉及函数调用、返回地址保存、寄存器保存等操作

循环:简单的跳转指令,几乎没有上下文切换开销

缓存效率

堆栈:频繁的函数调用可能导致缓存失效

循环:代码局部性更好,缓存命中率更高

和For循环的区别

和For循环的区别有很多,但我主要想讨论他们对解决问题的思考方式上的差别。这个也是我想让大家理解的第二层含义。

如果说递归的第一层含义是:自己调用自己。

那么递归的第二层含义是:上一次的函数输出,可以成为下一次函数的输入。

案例——阶梯问题:

我们以爬楼梯问题为例:有n阶台阶,每次可以爬1或2阶,问有多少种不同的方法爬到楼顶?

这实际上就是求斐波那契数列。

递归终止条件:

当 n=1 时,只有1种方法:爬1阶。

当 n=2 时,有两种方法:一次爬2阶,或者两次各爬1阶。

对于n>2的情况,考虑第一步有两种选择:

第一步爬1阶,那么剩下的n-1阶台阶有 climb_stairs_recursive(n-1) 种方法。

第一步爬2阶,那么剩下的n-2阶台阶有 climb_stairs_recursive(n-2) 种方法。

因此,爬n阶台阶的方法数等于这两种情况的方法数之和,即:

climb_stairs_recursive(n) = climb_stairs_recursive(n-1) + climb_stairs_recursive(n-2)

举个例子:n=3

第一步爬1阶,剩下2阶:有2种方法(爬2阶:一次2阶,或两次1阶)

第一步爬2阶,剩下1阶:有1种方法(爬1阶)

所以总共2+1=3种方法。

同理,n=4:

第一步爬1阶,剩下3阶:3种方法(上面n=3的情况)

第一步爬2阶,剩下2阶:2种方法(n=2的情况)

所以总共3+2=5种。

想要知道4阶有多少种,那么需要先知道3阶有多少种?

那么,想知道3阶有多少种,那么就得知道2阶有多少种?

一直追问到终止条件为止。

def climb_stairs_recursive(n):

# 基础情况

if n == 1:

return 1 # 只有1种方法:走1步

if n == 2:

return 2 # 2种方法:1→1 或 2

# 递归关系:f(n) = f(n-1) + f(n-2)

return climb_stairs_recursive(n-1) + climb_stairs_recursive(n-2)

为了方便理解,加上了打印参数:

def climb_stairs_recursive(n, depth=0):

indent = " " * depth # 根据深度缩进,显示调用层次

print(f"{indent}-> climb_stairs({n})")

# 基础情况

if n == 1:

print(f"{indent}<- 返回 1 (基础情况: n=1)")

return 1

if n == 2:

print(f"{indent}<- 返回 2 (基础情况: n=2)")

return 2

# 递归调用

print(f"{indent} 计算 climb_stairs({n - 1}) + climb_stairs({n - 2})")

left = climb_stairs_recursive(n - 1, depth + 1)

right = climb_stairs_recursive(n - 2, depth + 1)

result = left + right

print(f"{indent}<- 返回 {result} = {left} + {right}")

return result

print("计算 climb_stairs(5):")

print(f"最终结果: {climb_stairs_recursive(5)}")

image

其实,这里会造成重复计算,和写法有关,相当于开启了两个递归。

-> climb_stairs(4)

计算 climb_stairs(3) + climb_stairs(2)

-> climb_stairs(3)

对比for循环的写法:

# 需要在写代码的时候,自己维护状态

def climb_stairs_iterative(n):

if n <= 2:

return n

a, b = 1, 2

for i in range(3, n+1):

a, b = b, a + b

return b

在台阶问题(比如爬楼梯,每次可以走1步或2步,问n阶台阶有多少种走法)中,递归和循环都可以实现,但各有优劣。

递归方式的优点:

代码直观,易于理解:递归往往能够直接反映问题的数学定义,比如斐波那契数列、爬楼梯问题的递推关系。

易于设计和实现:对于复杂问题,递归可以简化设计过程。

但是,在台阶问题中,递归的缺点也很明显:

效率低:存在重复计算(递归层越大,重复计算则越多),导致指数级的时间复杂度。

栈溢出风险:当n较大时,递归深度过深,会导致栈溢出。

而循环(动态规划)方式则通过迭代和保存中间结果,避免了重复计算,时间复杂度为O(n),空间复杂度可以优化到O(1)。

总结

在快速原型阶段,可以使用递归是实现算法,好处是:

快速验证算法思路

更容易修改和调整逻辑

方便快速实现。

而到了中后期的优化阶段,可以考虑把循环结构改成动态规划(for)循环,以节省内存资源。

还有,

递归在直观性和易于实现数学定义是其主要优点,但在内存性能上不如循环结构(动态规划)。如果一个问题在初期就很容易用循环结构想清楚,则完全必要使用递归(没必要画蛇添足)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 22:18:40

零成本AI革命:gpt4free-ts开源项目深度解析与实战指南

引言&#xff1a;AI应用的新时代机遇 【免费下载链接】gpt4free-ts Providing a free OpenAI GPT-4 API ! This is a replication project for the typescript version of xtekky/gpt4free 项目地址: https://gitcode.com/gh_mirrors/gp/gpt4free-ts 在当前AI技术飞速发…

作者头像 李华
网站建设 2026/4/16 13:16:09

Graphiti知识图谱实战指南:从零搭建AI记忆系统的完整方案

Graphiti知识图谱实战指南&#xff1a;从零搭建AI记忆系统的完整方案 【免费下载链接】graphiti 用于构建和查询时序感知知识图谱的框架&#xff0c;专为在动态环境中运行的 AI 代理量身定制。 项目地址: https://gitcode.com/GitHub_Trending/grap/graphiti 你是否曾为…

作者头像 李华
网站建设 2026/4/16 12:07:18

高频信号能定位转子?这事儿听着有点玄乎,但旋转高频注入法确实让永磁同步电机甩掉了位置传感器。今天咱们就拆解这个黑科技,手把手看看怎么用代码实现无位置控制

旋转高频注入法永磁同步电机无位置控制策略&#xff0c;转子位置效果很好。 旋转高频电压注入法是通过在电机绕组端上注入三相对称的高频电压信号作为激励&#xff0c;检测 该激励信号产生的电流响应&#xff0c;通过特定的信号处理&#xff0c;最终获得转子位置与转速信息&…

作者头像 李华
网站建设 2026/4/16 3:28:52

踩下电门瞬间,电动车总有个让人着迷的爆发力。这背后藏着复合电源系统的精妙配合,今天咱们拆开看看这个由电池组、超级电容和DCDC组成的能量组合怎么玩转瞬态功率

基于规则策略的纯电动汽车复合电源仿真模型&#xff0c;包括DCDC模型、电池模型&#xff0c;超级电容模型。先看动力电池的建模。这里用二阶RC等效电路能比较好地反映动态特性。试着用Python搭个简化模型&#xff1a; class BatteryModel:def __init__(self, soc0.8):self.soc …

作者头像 李华
网站建设 2026/4/16 13:15:31

先扔个核心代码镇楼

蒙特卡洛法&#xff08;mc&#xff09;模拟晶粒生长 利用仿真软件abaqus、ansys或其他软件模拟熔池的宏观温度场&#xff0c;并用matlab编写晶粒生长程序&#xff0c;将温度写入程序接口&#xff0c;微观模拟该温度下晶粒生长的过程。 内容包括程序源代码、参数设置视频教程% 蒙…

作者头像 李华
网站建设 2026/4/16 13:23:12

ffmpeg-python视频降噪实用指南:从基础应用到高级技巧

ffmpeg-python视频降噪实用指南&#xff1a;从基础应用到高级技巧 【免费下载链接】ffmpeg-python Python bindings for FFmpeg - with complex filtering support 项目地址: https://gitcode.com/gh_mirrors/ff/ffmpeg-python 视频处理中噪声问题一直困扰着许多创作者&…

作者头像 李华