【问题标题】:Unable to understand Recursivly calling same method with two different input无法理解使用两个不同的输入递归调用相同的方法
【发布时间】:2018-01-23 09:29:59
【问题描述】:

我最近开始接触递归。我浏览了一些可用的在线文档,但无法理解当我们使用不同的输入调用相同的方法时,递归调用是如何工作的。

假设,如果我见过树

return find(node.left) + find(node.right);

我无法理解它是如何工作的。

在一般递归中,每次调用都会在堆栈中占有一席之地,当达到基本条件时,我们计算并返回结果。 我试着做一个小程序,我从两个不同的调用者用不同的索引调用相同的方法,如果达到基本条件,则添加两个返回值。

if(n==0){
        return arr[n];
    }

    else {
        return calculateSum(arr, n-1) + arr[n];
    }

代码运行良好。现在我继续前进并尝试了这样的事情。

它给了我堆栈溢出

if(n==1){
        return arr[n];
    }

    else {
        return calculateSum(arr, n-1) + calculateSum(arr, n-2);
    }

我完全无法理解它是如何发生的,我错过了这个主题以无法完全理解它。

我根据提供的建议更改了我的代码。但无法理解流程。 n-2 是如何运作的。我给了一些打印。请在下面找到打印和代码。

private static int calculateSum(int[] arr, int n, String caller){

    if(n<=1){
        System.out.println(caller+" : "+n+ " : "+arr[n]);

        return arr[n];
    }

    else {
        return calculateSum(arr, n-1," minus one") + calculateSum(arr, n-2,"minus two");
    }


}

打印:

减一:1:2

减二:0:1

减二:1:2

减一:1:2

减二:0:1

减一:1:2

减二:0:1

减二:1:2

数组总和:13

如果有人可以帮助我了解它是如何工作的。我想知道 减二 值是如何在开始时变为 0,然后变为 1。为什么 减一 在减二后又被调用一次达到了基本条件。

注意:我已经删除了带有 return 语句的 arr[n]。所以,现在我想了解调用以及它是如何工作的。

【问题讨论】:

  • 我想确认一下如果你改成if (n &lt;= 1) 是否还会出现问题?我相信你在这里的递归实际上并没有结束。
  • @NelsonYeung:该更改将防止溢出,但现在可以尝试访问arr[0]
  • @ScottHunter 你为什么不想要arr[0]?我以为你想要整个数组?
  • @NelsonYeung:发布的代码(至少最终版本)不包含它。
  • 发布了代码中发生的详细信息。请检查它可能对您有帮助

标签: algorithm recursion data-structures tree


【解决方案1】:

您的最后一个版本的程序有很多问题,其中最重要的是数组中唯一包含在总和中的元素是arr[1]

然而,堆栈溢出的原因是可能会在第二个参数为 0 的情况下生成对 calculateSum 的调用(例如,当 n==2 时的第二次递归调用),这将使基本情况测试,并且由于后续递归调用的 n 值更小,因此永远不会成功。

我发现思考递归最有帮助的方法是想象其他人已经编写了一个函数来解决您的问题的“较小”版本(例如,任何子树,或任何较小的 n 值) ; 任何合适的)。编写 您的 函数以使用该函数,确保 a) 每当您调用它时,它与问题的较小版本有关,并且 b) 如果您有足够小的问题版本您可以在没有递归调用的情况下解决,不要进行递归调用。 (请注意,如果您将这种技术应用于您的最后一段代码,您可以看到,即使递归调用正常工作,您也会重复计算大部分数组。很明显,您的早期版本是正确。)

神奇之处在于:通过执行我上面描述的操作,您已经编写了您认为是其他人编写的函数。

【讨论】:

  • 更正了代码,但无法理解调用的方式,用打印更新了代码。如果你能帮助我一点。
  • 您没有更正代码;您只是避免了堆栈溢出,这更好,但不足以使其正确。
【解决方案2】:

在这种情况下,您没有应用正确的基本条件

看,你的程序:-

cal(arr,n){
if(n==1){
        return arr[n];
    }

    else {
        return calculateSum(arr, n-1) + calculateSum(arr, n-2);
    }

}

现在举个例子,arr = [1,2,3] n = 3

Cal(arr,3){
// Base condtn fails
Recursion takes place now
cal(arr,2) + cal(arr,1);

}

现在,执行

cal(arr,2){
// Base condtn fails
Recursion takes place now
cal(arr,1) + cal(arr,0);
}

现在,执行

cal(arr,1){
// Base condtn true return arr[1]
}

现在,执行

cal(arr,0){
// Base condtn fails here also stackoverflow now never returning
}

虽然无法通过此递归找到总和,但请使用此

cal(arr, n)
{
    if (n <= 0)
        return 0;
    return (cal(a, n-1) + arr[n-1]);
}

【讨论】:

  • 这将永远不会包含总和中索引 >= 1 的任何元素。
  • 谢谢。我已经更正了代码,现在它正在工作。但无法理解呼叫流程。我已经给出了一些打印但无法理解呼叫流程。注意:我已将条件更改为 (n减一:1:2 减二:0:1 减二:1:2 减一:1:2 减二:0:1 减一:1 : 2 减二 : 0 : 1 减二 : 1 : 2 数组之和 :13
  • @SanketSaha 很高兴为您提供帮助。如果您在递归中遇到任何问题,请始终尝试使用简短示例
  • if(n&lt;1) { return arr[n] } 永远不会从arr 返回索引>= 1 的元素;因为这是代码中唯一直接从arr 中提取值的部分,它适用于整个函数。
  • @SanketSaha 使用一些简短的例子。它将帮助您解决问题
猜你喜欢
  • 2010-09-28
  • 2021-05-16
  • 1970-01-01
  • 2013-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多