调用自己的方法..递归?

时间:2014-02-06 01:21:09

标签: java recursion methods call

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,那就是返回的值。它是否正确?如果是这样的话,更深入的解释会很好。

3 个答案:

答案 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提取调试信息真的很难(你需要模拟它的工作)。在接受工作面试时,您通常会使用计算机来测试代码 - 您的分析技能正在接受测试。这就是为什么我强烈推荐使用铅笔&在查看代码执行时真正做的事情之前的纸张方法。

问题1:返回值

当试图分析复杂的代码时,知道你可以忽略的是成功的关键。

你知道吗

  • 代码是单线程的,
  • 没有全局变量,对当前呼叫之外的世界没有副作用,
  • 未使用递归调用的返回值。

所以没有必要考虑来自其他线程的混乱,你可以分析单个调用而不考虑递归调用会如何影响它(除了返回值)并且你可以忘记递归调用,除非它是无限递归(它不会让你的程序终止),因为它对消耗时间没有影响。

递归不是无限的,因为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

问题2:通话次数

递归是线性的 - 每次调用最多只进行一次递归调用。因此,您必须计算到达递归底部所需的调用次数。

递归的底部是条件的第一个分支。因此,您需要计算在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。另外一个是最顶级的电话。这是一般答案。