递归与调用栈

这个页面在做什么。上方是调用树,下方是调用栈,右侧是对应的 Java 代码。按单行推进时,高亮行是当前执行位置,栈帧从下往上堆叠,栈顶那一帧白框标出。调用栈是 JVM 替你维护的,代码里看不到它——这里把它画出来。

递归四步。契约:先定死这个函数对任意输入返回什么。基线:最小的输入直接给答案,不再递归。分解:拆成同形状的更小问题。合并:用子问题的答案拼出自己的答案。四步齐了,函数就是对的。

递归的信任。写第 4 行时不要在脑子里展开 maxDepth(root.left),就当它已按契约返回了左子树的深度。展开是 JVM 的事。

执行顺序不是「先冲到最深再一路返回」。每一层都在做同一件事:下去 → 回来 → 继续下一句。第 4 行返回后停在第 5 行,这时才轮到右子树——右边的整棵树在此之前一步都没动。

栈的位置。BFS 那页里队列是你自己声明的 ArrayDeque;这里的调用栈同样是个容器,只是 LIFO,且由 JVM 维护。栈帧里存的就是每层的 rootLR。递归深度直接等于栈高,栈溢出就是这里放不下了。

关键的一步。某一帧触底返回时它收起消失,返回值落进紧邻下方那一帧的 LR(黄色闪一下)。整个递归的信息只沿这一条路径回流,别处没有通道。

记忆化。斐波那契不加缓存时 fib(n-1)fib(n-2) 的子树大量重叠,调用次数 O(2ⁿ);缓存让每个 n 只算一次,降到 O(n)。哨兵值不能用 0——fib(0) 的真实答案就是 0,用 0 判空会把它当成未命中反复重算,这里用 -1

快捷键。空格 播放 / 暂停, 单行推进,R 重置。焦点在滑块上时按键归滑块。树递归模式下点击任意节点可把它设为新的根。

n10 速度
未访问 已进入未返回 已返回 当前栈顶 缓存命中
调用栈 · maxDepth 栈高 0 · 峰值 0
栈为空

    
就绪。按「单行」开始,或点「播放」。