递归的运行过程

来源:互联网 发布:qp个案分析比赛知乎 编辑:程序博客网 时间:2024/06/04 23:23

说起树的递归遍历,斐波那契的递归遍历,都能很快写出来。但是昨天同学问我下面这段代码中,递归具体的执行过程,我却没能说清楚:
1 if(root==null){
2 return 0;
3 }
4 int left=maxDeepth(root.left);
5 int right=maxDeepth(root.right);
6 return left>right?left+1:right+1;

很明显这在求树的深度。那么程序执行到第四行时,会不会先将left的递归调用压入虚拟机栈中继续向下执行,一直到return。这个算法的思想很简单,但是结合到具体的执行原理,就讲不清了。接下来是研究心得:
首先假设有这样一棵树:
在和同学的讨论中,将上面的代码做了调整:
if (root == null) {
return 0;
}
System.out.println("当前节点值:"+root.val+" 左树开始时间:"+System.nanoTime()+"\n");
int left = maxDeepth(root.left);
System.out.println("当前节点值:"+root.val+" 右树开始时间:"+System.nanoTime()+"当前节点左树深度值:"+left+"\n");
int right = maxDeepth(root.right);
System.out.println("当前节点值:"+root.val+" 树的结束时间:"+System.nanoTime()+"当前节点右树深度值:"+right+"\n");
return left > right ? left + 1 : right + 1;

就是将程序在运行时的前后时间打印出来,本意是向看前后时间相差是否不大,不大就说明程序在left执行后继续向下执行了。
执行后的结果如下:
当前节点值:0 左树开始时间:510388681116877

当前节点值:1 左树开始时间:510388686269259

当前节点值:3 左树开始时间:510388686362565

当前节点值:7 左树开始时间:510388686406886

当前节点值:7 右树开始时间:510388687154737 当前节点左树深度值:0

当前节点值:7 树的结束时间:510388687365609 当前节点右树深度值:0

当前节点值:3 右树开始时间:510388687512567 当前节点左树深度值:1

当前节点值:8 左树开始时间:510388688146584

当前节点值:8 右树开始时间:510388688674232 当前节点左树深度值:0

当前节点值:8 树的结束时间:510388688760540 当前节点右树深度值:0

当前节点值:3 树的结束时间:510388689409020 当前节点右树深度值:1

上面是一部分结果。由上面的结果分析,程序从树的根节点开始,第一次执行到left=maxDeepth(root.left)时,并没有继续向下,而是停在了这一句,它开始递归,此处不得不提虚拟机栈的一部分知识:
1.在JVM栈中每调用一次方法就会做一次入栈操作,在栈中保存为一个栈帧(存储方法的局部变量,操作数栈,动态链接,方法返回地址和一些额外的附加信息)。
2.在JVM栈中永远都是底层栈帧调用上层栈帧。
假设栈帧就是一个方法的副本(当然真正的远比这复杂),不影响分析。
下面的每一次调用都会入栈产生栈帧,出栈产生结果给下一层栈帧。
那么现在0节点入栈了,它执行到left这行,发现要调用一个方法,才能拿到值,所以它根据条件向自己的左儿子节点1要个说法,节点1又向节点3要,3又向7要,7继续向自己的左儿子要结果,但7的左儿子没有是null,所以终于有了确切的结果,返回了0,所以在7这个方法副本中可以继续向下走了,又找7的右节点要结果,这次不用费时间,右,儿子也干净利落的也给了它老子一个0,7号节点所在的这层副本里终于要产生自己最终结果了,7号在比较之后发现自己儿子们的最大身高是0,那么加上7自己这1厘米的身高,就是全家的身高,所以返回了1,此时7这一家从JVM栈中出去了,它的下层副本就是节点3,那么3这层副本呢,既然拿到了自己左儿子的准确身高,就可以向下走了,所以又去问自己的右儿子节点8,同样的道理,8又将自己的左儿子入栈、出栈,之后将自己的右儿子入栈、出栈,获得了自己的最大高度是1,节点3这层副本也就能从栈中出去了,它交出自己的结果给下层副本………………
到了这里过程也就很清楚了,递归方法执行到需要递归的地方的时候,不会如代码的过程一样直接继续执行,假设这层的代码就是公式,JVM会去推理,术语叫做递推,得到结果后又一层层把结果带回来,术语叫回溯。这就好像是程序员告诉虚拟机:去吧,皮卡丘,把胜利的果实带回来,然乎皮卡丘又对自己的孩子说:去吧,皮卡丘,把胜利的果实带回来…………然后最小的皮卡丘最终不负期望带回了胜利,一层层把胜利传递回来给程序员。
每一次知道解决问题的原理时,真是相当爽。。
在这里记录一下,让自己以后可以回忆一下

原创粉丝点击