Algorithm 无法理解使用两个不同的输入递归调用同一个方法

Algorithm 无法理解使用两个不同的输入递归调用同一个方法,algorithm,recursion,data-structures,tree,Algorithm,Recursion,Data Structures,Tree,我最近开始接触递归。我已经阅读了一些可用的在线文档,但无法理解当我们使用不同的输入调用同一个方法时递归调用是如何工作的 假设我看到了一棵树 返回find(node.left)+find(node.right) 我不明白这是怎么回事 在一般的递归中,每个调用在堆栈中都有一个位置,当基本条件达到时,我们计算并返回结果。 我试着做一个小程序,从两个不同的调用方调用相同的方法,使用不同的索引,如果达到基本条件,则添加两个返回值 if(n==0){ return arr[n]; }

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

假设我看到了一棵树

返回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");
    }


}
private static int calculateSum(int[]arr,int n,字符串调用者){

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

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

我发现,思考递归最有帮助的方式是,假设其他人编写了一个函数,该函数可以解决问题的“较小”版本(例如,任何子树,或任何较小的n值;任何合适的值)无论何时调用它,都是使用问题的较小版本,并且b)如果问题的较小版本不需要递归调用就可以解决,则不要进行递归调用。(请注意,如果将此技术应用于最后一段代码,您可以看到,即使递归调用工作正常,也会重复计算大部分数组。很明显,您的早期版本是正确的。)


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

您的上一个版本的程序存在许多问题,其中最重要的问题是,数组中唯一包含的元素是
arr[1]

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

我发现,思考递归最有帮助的方式是,假设其他人编写了一个函数,该函数可以解决问题的“较小”版本(例如,任何子树,或任何较小的n值;任何合适的值)无论何时调用它,都是使用问题的较小版本,并且b)如果问题的较小版本不需要递归调用就可以解决,则不要进行递归调用。(请注意,如果将此技术应用于最后一段代码,您可以看到,即使递归调用工作正常,也会重复计算大部分数组。很明显,您的早期版本是正确的。)


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

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

请看,您的程序:-

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,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]);
}
cal(arr,n)
{

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

请看,您的程序:-

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,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]);
}
cal(arr,n)
{

if(n)我想确认您是否更改为
if(n@NelsonYeung:该更改将防止溢出,但现在可以尝试访问
arr[0]
@ScottHunter。您为什么不想
arr[0]
呢?我以为您想查看整个数组?@NelsonYeung:发布的代码(至少是最终版本)不包括它。发布了代码中发生的详细情况。请检查它是否对您有帮助我想确认您是否更改为
if(n@NelsonYeung:该更改将防止溢出,但现在可以尝试访问
arr[0]
@ScottHunter为什么不想要
arr[0]
无论如何?我还以为你想看看整个阵列?@NelsonYeung:发布的代码(至少是最终版本)不包括它。发布了代码中发生的详细情况。请检查它可能会对您有所帮助。这将永远不会在总和中包含索引>=1的任何元素。谢谢。我已经更正了代码,现在它正在工作。但无法理解呼叫流。我已经打印了一些内容,但无法理解呼叫流。注意:我已更改了co预告(n@SanketSaha很高兴帮助您。如果您在递归
if(n=1;因为这是