public static int m(int i, int j)
{
if ( i > j)
return 0;
else
{
i++;
m(i++, j);
}
return i;
}
我有两个问题。 1.)out.print(m(3,8));
和2返回的内容。)调用方法的次数是多少次?答案应分别为5和7。
当我解决问题1时,我出来了5但是我做的方式不正确,因为该方法没有被调用7次,它只被调用了两次。我这样做的方式是我直接进入了else语句,因为(i > j)
在开始时是假的,这次用(4, 8)
再次调用方法m我觉得它仍然是假的所以我回到了由于i++
中的m(i++, j)
,调用m并且变量i变为5的行。之后,它将为i的值返回5。
这显然是错误的,所以我在整个程序中为i的值添加了一些out.print,以查看值是如何变化的,并且在方法{{的开头用out.print(i);
从3变为9 1}}。在m
之前的out.print(i);
显示值开始从10回到5并且该方法被调用7次。这是如何工作的?
方法m在开始时以3,8调用。之后,它调用自身4,8然后5,8 ....直到9,8,其中if语句变为true并且方法返回0.它自己调用6次因此它开始向后或减少6次因此因为m(i ++,j)是post(i)然后我变成10并返回10,然后是9,然后是8,然后是7,6,最后是5.当它返回10时为1,9是2,8是3,7是4,6是5,5是6.因为当i = 5时它是6,那就是返回的值。它是否正确?如果是这样的话,更深入的解释会很好。
答案 0 :(得分:3)
您看到值减少的原因是因为在打印最后一个'i'之前,此值仅在本地范围内增加(在您的其他条件中为第一个i ++)。
当你的m函数返回到它的调用者时,我不再像在子节点中那样i + 1,因此你会看到递减的值,直到返回根'm'调用。
答案 1 :(得分:1)
为了更好地理解正在发生的事情,可能有助于重构代码:
public static int m(int i, int j) {
static int calls = 0;
System.out.println("entering. count: " + calls);
calls++;
System.out.println("i = " + i);
System.out.println("j = " + j);
if (i > j) {
System.out.println("returning 0");
return 0;
} else {
i++;
m(i++, j);
}
System.out.println("returning " + i);
return i;
}
请注意,我没有修改任何实际逻辑。我所做的就是为打印值添加一些语句,并使用一个变量来跟踪调用方法的次数。
答案 2 :(得分:1)
我将在一般情况下分析函数,具体的参数值将仅在最后使用。当你有这样的工具时,运行该功能并通过调试器或调试打印来观察它的功能是很方便的,但在某些情况下你只能依靠你的大脑。例如。从FPGA提取调试信息真的很难(你需要模拟它的工作)。在接受工作面试时,您通常会使用计算机来测试代码 - 您的分析技能正在接受测试。这就是为什么我强烈推荐使用铅笔&在查看代码执行时真正做的事情之前的纸张方法。
当试图分析复杂的代码时,知道你可以忽略的是成功的关键。
你知道吗
所以没有必要考虑来自其他线程的混乱,你可以分析单个调用而不考虑递归调用会如何影响它(除了返回值)并且你可以忘记递归调用,除非它是无限递归(它不会让你的程序终止),因为它对消耗时间没有影响。
递归不是无限的,因为i
总是在递归调用之前递增,递归在i > j
时停止。
知道这一点,决定返回值是多么容易。该功能可以简化为
public static int m(int i, int j)
{
if (i > j)
return 0;
else
i += 2;
return i;
}
因为return终止了函数的执行,所以甚至可以进一步减少到
public static int m(int i, int j)
{
return (i > j) ? 0 : i + 2;
}
给出问题1的答案。当被称为m(3, 8)
时,结果为0
,因为i
小于j
。
递归是线性的 - 每次调用最多只进行一次递归调用。因此,您必须计算到达递归底部所需的调用次数。
递归的底部是条件的第一个分支。因此,您需要计算在i > j
之前拨打电话的次数。
j
在每个调用中具有相同的值。没有命令可以更改其值,它总是传递给递归调用不变。 i
总是在递归调用之前和调用之后递增一次(i++
是后递增,在使用原始值之后取得效果)。只有第一个增量与递归调用相关。
为了计算递归调用,函数可以简化为
public static void m(int i, int j)
{
if (i > j)
return;
else
m(i + 1, j);
}
由此可见,i
连续递增1,直到它大于j
。
在m(3, 8)
中,来电是
m(3, 8)
,m(4, 8)
,m(5, 8)
,m(6, 8)
,m(7, 8)
,m(8, 8)
和m(9, 8)
。所以有7个。
如果给出的参数差异较大,一般解决方案都很方便。所以让我们来探索吧。这会很快。
如果最初是i > j
,那么显然只会进行一次通话。否则......从i
计算到j + 1
时,您会遇到多少个数字? (j + 1) - i + 1 = j - i + 2
。另外一个是最顶级的电话。这是一般答案。