递归逻辑求助:无法理解range递归函数的递归步骤运行原理
递归版range函数运行原理解答
首先明确递归的两个核心运行规律,所有递归逻辑都符合这两个规律,不用把它想成特殊的语法:
- 递归函数的返回值类型,永远和基线条件(base case)的返回值类型一致
- 递归执行是先逐层向内调用直到命中基线条件,再从最内层开始逐层向外返回,执行每层调用中递归语句之后的逻辑,不是单次从上到下跑完所有代码。
针对两个疑问的具体解答
1. 为什么numbers变量是数组类型?
你不需要额外定义range是数组,函数的返回值类型由return语句的结果决定:
- 代码里两个基线条件的返回值都是数组:
end < start时返回空数组[],start == end时返回单元素数组[start] - 所有递归分支最终都会走到基线条件,因此任意合法参数下调用range,返回值一定是数组。
const numbers = range(start, end - 1)本质是把内层range调用返回的数组赋值给numbers,它自然就是数组类型。
我们拿实际调用range(1,3)拆解完整执行流程,你就能看明白:
- 第一层调用:入参start=1、end=3,不满足基线条件,执行到
range(1, 2)时暂停,等待内层调用返回结果后才会继续执行push操作 - 第二层调用:入参start=1、end=2,不满足基线条件,执行到
range(1, 1)时暂停,等待内层返回 - 第三层调用:入参start=1、end=1,命中基线条件,直接返回数组
[1] - 回到第二层调用:numbers接住返回的
[1],执行push(2),数组变为[1,2],将该结果返回给上一层 - 回到第一层调用:numbers接住返回的
[1,2],执行push(3),数组变为[1,2,3],返回最终结果
2. 为什么修改为传入start + 1再push start会得到倒序结果?
修改后的代码逻辑如下:
function range (start, end) { if (end < start) return []; if(start == end) { return [start]; } else { const numbers = range(start + 1 , end); numbers.push(start) return numbers; } }
还是拿range(1,3)拆解流程,倒序的原因非常直观:
- 第一层调用:入参start=1、end=3,暂停等待
range(2,3)返回 - 第二层调用:入参start=2、end=3,暂停等待
range(3,3)返回 - 第三层调用:入参start=3、end=3,命中基线条件,返回数组
[3] - 回到第二层调用:numbers接住
[3],执行push(2),数组变为[3,2],返回给上一层 - 回到第一层调用:numbers接住
[3,2],执行push(1),数组变为[3,2,1],自然就是倒序。
本质原因是push操作永远在递归调用返回之后才执行,执行顺序是从最内层到最外层:你调整递归入参后,最内层基线条件返回的是区间最大值,逐层向外push的是逐次减小的start值,最终结果当然是倒序。
递归练习实操建议
不用硬啃太多教学视频,初练的时候别靠脑子硬扛多层调用栈,人脑的临时记忆深度撑不住3层以上的递归:
- 每次写递归先写基线条件,先明确函数最终要返回什么类型的值,基线条件直接返回该类型的确定结果
- 写递归步骤的时候,直接假设「缩小规模后的递归调用已经能返回正确结果」,你只需要在这个结果上做一步操作得到当前规模的结果就行,不用去想内层递归具体怎么跑。比如写正序range的时候,你就直接假设
range(start, end-1)已经能返回start到end-1的正确数组,你只要往末尾加个end就完成了。 - 刚开始练的3-5个题,拿笔把每一层的入参、等待的内层调用、拿到返回值后要做的操作逐行列出来,列完几次自然就找到感觉了。
内容的提问来源于stack exchange,提问作者SyntaxJunkie
相关产品推荐
相关产品推荐

