我知道递归函数是什么以及我如何可视化堆栈顶部的每个递归调用。但我不知道如何在函数多次调用自身时如何思考
float foo(int n){
int a = 0;
for(int i = 0; i < n; i++)
a += 1;
if (n > 2)
return foo(n/2) + foo(n/2); // What happens here?
return a;
}
我现在想到两个不同的堆栈或者可视化结果的最佳方法是什么?
答案 0 :(得分:2)
正如其他提到的答案,只有一个堆栈和递归调用严格按给定的顺序进行评估。
但是,出于分析目的,您可以将整个呼叫序列可视化为树。
答案 1 :(得分:1)
return foo(n/2) + foo(n/2); // What happens here?
第一个表达式在第二个表达式评估之前完全评估。这与两个不同的堆栈无关。第一个调用的一个堆栈在计算时会扩展和收缩,一旦完全计算了这个表达式,第二个就会开始。
这有助于形象化吗?
答案 2 :(得分:1)
我现在想到两个不同的堆栈或者最好的方法是什么 可视化结果?
它仍然是一个堆栈。在这一行:
return foo(n/2) + foo(n/2); // What happens here?
...将首先评估对foo()的一个调用(将其参数和局部变量推送到堆栈,使用,然后再次从堆栈中弹出),然后另一个将是以同样的方式评估。 (请注意,在语言规范中未定义首先评估foo()调用,因此由编译器的实现者来决定他们喜欢的顺序。
答案 3 :(得分:1)
让我们尝试为调用foo(4)的不同阶段可视化堆栈(是的,只有一个堆栈):
在调用foo(4)之前:调用者堆栈
在原始调用foo(4)中:stack = 调用者堆栈,foo(4)
当foo(4)在第一次调用foo(2)时:调用者堆栈,foo(4),foo(2)
foo(4)在foo(2)的第一次调用中,其中foo(2)已经调用了第一个foo(1):调用者堆栈,foo(4),foo(2),foo( 1)强>
从第一个foo(1)返回后:再次调用者堆栈,foo(4),foo(2)
foo(4)在foo(2)的第一次调用中,其中foo(2)调用了第二个foo(1):调用者堆栈,foo(4),foo(2),foo(1) )强>
从第二个foo(1)返回后:再次调用者堆栈,foo(4),foo(2)
从第一个foo(2)返回后:来电堆栈,foo(4)
foo(4)在第二次调用foo(2)之内:调用者堆栈,foo(4),foo(2)
foo(4)在foo(2)的第二次调用中,其中foo(2)已经调用了第一个foo(1):调用者堆栈,foo(4),foo(2),foo( 1)强>
从第一个foo(1)返回后:再次调用者堆栈,foo(4),foo(2)
foo(4)在foo(2)的第二次调用中,其中foo(2)调用了第二个foo(1):调用者堆栈,foo(4),foo(2),foo(1) )强>
从第二个foo(1)返回后:再次调用者堆栈,foo(4),foo(2)
从第二个foo(2)返回后:来电堆栈,foo(4)
从foo(4)返回后:来电堆栈