因此,在我的一堂课上,我正在学习递归,我试图找出一个问题,但是找不到正确的答案。
我一直得到11,但正确的答案是6。有人可以帮助我获得更好的理解,并希望解释一下如何跟踪代码。谢谢。
我现在的追踪方式:
int f(int x, int y) {
if (x <= 0) {
return y;
}
return f(x - 1, y + 1) - f(x / 2, y * 2);
}
What is f(4, -1)?
f(4,-1)
return f(3,0) - f(2,-2)
return f(2,1) - f(1,-4)
return f(1,2) - f(0,-8)
return f(0,3) - (-8)
return 3 + 8 = 11.
答案 0 :(得分:4)
您没有考虑到对 <script src="https://www.gstatic.com/firebasejs/7.8.0/firebase-admin.js"></script>
的呼叫中的大部分正在对f()
进行 2 内部呼叫。因此,真正的痕迹将更像以下那样分解。真正的答案是f()
,而不是您的教授告诉您的2
:
6
答案 1 :(得分:1)
这是具有递归调用控制流的ASCII艺术,
f(4,-1)-------->+
. //f(4 - 1, -1 + 1)
. f(3,0)------->+
. . |
. . //f(3-1,0+1)
. . f(2,1)----------->+
. . . |
. . . // f(2-1,1+1)
. . . f(1,2)--------->+
. . . . |
. . . . //f(1-1,2+1)
. . . . f(0,3)--------->+
. . . . . //as (x == 0) return 3
. . . . . |
. . . . |<----(3)---+
. . . . |
. . . . //f(1/2,2*2)
. . . . f(0,4)--------->+
. . . . . //as (x == 0) return 4
. . . . . |
. . . . +<----(4)---+
. . . . |
. . . . //f(1-1,2+1) - f(1/2,2*2) = 3 - 4 = -1
. . . +<---(-1)---+
. . . |
. . . // f(2/2,1*2)
. . . f(1,2)--------->+
. . . . |
. . . . //f(1-1,2+1)
. . . . f(0,3)--------->+
. . . . . //as (x == 0) return 3
. . . . . |
. . . . +<----(3)---+
. . . . |
. . . . //f(1/2,2*2)
. . . . f(0,4)--------->+
. . . . . //as (x == 0) return 4
. . . . . |
. . . . +<----(4)---+
. . . . |
. . . . //f(1-1,2+1) - f(1/2,2*2) = 3 - 4 = -1
. . . +<---(-1)---+
. . +<----(0)-------+
. . |
. . //f(3/2,0*2)
. . f(1,0)----------->+
. . . |
. . . //f(1-1,0+1)
. . . f(0,1)--------->+
. . . . //as (x == 0) return 1
. . . . |
. . . +<----(1)---+
. . . |
. . . //f(1/2,0*2)
. . . f(0,0)--------->+
. . . . //as (x == 0) return 0
. . . . |
. . . +<----(0)---+
. . . |
. . . //f(0,1)-f(0,0) = 1- 0 = 0
. . +<-----(1)------+
. . |
. . // f(3-1,0+1) - f(3/2,0*) = 0 - 1 = -1
. +<----(-1)--+
. |
. //f(4/2,-1*2)
. f(2,-2)------->+
. . |
. . //f(2-1,-2+1)
. . f(1,-1)---------->+
. . . |
. . . //f(2-1,-2+1)
. . . f(0,0)--------->+
. . . . //as (x == 0) return 0
. . . . |
. . . +<----(0)---+
. . . |
. . . //f(1/2,-1*2)
. . . f(0,-2)-------->+
. . . . //as (x == 0) return -2
. . . . |
. . . +<---(-2)---+
. . . |
. . . //f(0,0)-f(0,-2) = 0 - (-2) = 2
. . +<----(2)-------+
. . |
. . //f(2/2,-2*2)
. . f(1,-4)---------->+
. . . |
. . . f(0,-3)-------->+
. . . . //as (x == 0) return -3
. . . . |
. . . +<---(-3)---+
. . . |
. . . f(0,-8)-------->+
. . . . //as (x == 0) return -8
. . . . |
. . . +<---(-8)---+
. . . |
. . . //f(0,-3) -f(0,-8) = -3 -(-8) = 5
. . +<-----(5)------+
. . |
. . //f(1,-1)-f(1,-4) = 2 - 5 = -3
. +<----(-3)--+
. |
. //f(4 - 1, -1 + 1) - f(4/2,-1*2) = -1 - (-3) = 2
<----(2)----+
如何理解,
<--(x)---
代表返回值x
调用函数f(x,y)时,将对f(x-1,y + 1)进行递归调用,直到x为零为止,然后递归调用f(x / 2,y * 2)。< / p>
请考虑以下情况,使用f(1,2)调用对f(0,3)和f(0,4)进行两次后续递归调用,并将两者的返回值作为f(1,2)的返回值进行计算)
f(1,2)--------->+
. |
. //f(1-1,2+1)
. f(0,3)--------->+
. . //as (x == 0) return 3
. . |
. |<----(3)---+
. |
. //f(1/2,2*2)
. f(0,4)--------->+
. . //as (x == 0) return 3
. . |
. +<----(4)---+
. |
. //f(1-1,2+1) - f(1/2,2*2) = 3 - 4 = -1
+<---(-1)---+
答案 2 :(得分:0)
如果需要,可以手动打印出迹线。在大多数情况下,它可能不如调试器好,但有时会派上用场。 https://godbolt.org/z/WpSYNj
#include <iostream>
int g_tabs = 0;
struct trace
{
trace(int x, int y)
{
for(int i = 0; i < g_tabs; ++i)
std::cout << " ";
std::cout << "f(" << x << ", " << y << ") {\n";
++g_tabs;
}
~trace()
{
--g_tabs;
for(int i = 0; i < g_tabs; ++i)
std::cout << " ";
std::cout << "}\n";
}
};
void print(int res)
{
for(int i = 0; i < g_tabs; ++i)
std::cout << " ";
std::cout << "result[ " << res << " ]\n";
}
void print(int l, int r, int res)
{
for(int i = 0; i < g_tabs; ++i)
std::cout << " ";
std::cout << "result[ " << res << " ] = " << l << " - " << r << '\n';
}
int f(int x, int y)
{
trace t(x, y);
if (x <= 0) {
print(y);
return y;
}
int left = f(x - 1, y + 1);
int right = f(x / 2, y * 2);
int result = left - right;
print(left, right, result);
return result;
}
int main()
{
f(5, 3);
return 0;
}