Java 无法理解这种递归

Java 无法理解这种递归,java,recursion,Java,Recursion,输入为{4,7,3,6,7},输出为: [81] [40, 41] [21, 19, 22] [11, 10, 9, 13] [4, 7, 3, 6, 7] 下面是我为此编写的递归程序,其中我添加了一些print语句来理解递归: import java.util.Arrays; public class triangle_array { public static void print(int a[]) { if(a.length==0)

输入为
{4,7,3,6,7}
,输出为:

[81]
[40, 41]
[21, 19, 22]
[11, 10, 9, 13]
[4, 7, 3, 6, 7]
下面是我为此编写的递归程序,其中我添加了一些print语句来理解递归:

import java.util.Arrays;

public class triangle_array {
    public static void print(int a[])
    {
        if(a.length==0)
            return;
        int n=a.length;
        int newa[]=new int[n-1];
        for(int i=0;i<n-1;i++)
        {
            newa[i]=a[i]+a[i+1];
        }
         System.out.println("here1") ;
        print(newa);
         System.out.println("here2") ;
        if(newa.length!=0)
        System.out.println(Arrays.toString(newa));
    }

    public static void main(String args[])
    {
        int a[]={4,7,3,6,7};
        print(a);
        System.out.println(Arrays.toString(a));
    }

}
我不能完全理解这种递归,
从上面的
这里
语句中,我了解到print methods首先被递归调用,当条件失败时,它返回到print之外,并到行中打印“here2”2次,并验证newa的长度为零,直到我理解这一点,但是在下一次迭代中,对于println语句,newa的长度是如何增加的?下面的条件是如何变为真的?

newa的长度不会增加,它总是减少一。最短的一个首先被打印,因为递归调用在打印数组的指令之前。所以它说“创建新的较短数组,但首先递归地处理它(包括打印),然后自己打印”


顺便说一下,这种结构有点奇怪。与在
print
方法的末尾打印
newa
相比,我认为打印
a
(如果周围没有
if
),然后您也不需要在
main
方法中打印将更有意义。

您的函数从

if(a.length==0)
        return;
因此,当
a
为空时,函数明显停止,但在这种情况下,当
a
连续给出一个0长度
a
来减少finish时,函数停止。因此,如果原始数组有4个条目,则函数将调用自身3次。5个条目将调用4次。等等正如每个调用本身可能回忆的那样,5个条目将调用functin,n给出一个4个条目的数组,wich给出一个3个条目的数组,直到得到一个单个条目的数组

int newa[]=new int[n-1];
for(int i=0;i<n-1;i++)
    {
        newa[i]=a[i]+a[i+1];
    }
首先显示较小的数组,因为当您调用函数时,它将调用自身,直到可能的最小数组。print的结构使得最后一个调用是第一个打印的,因为最后一个调用的函数将是第一个完成的,而另一个调用直到下面的级别没有完成才结束。这就是为什么你认为a在增加,你必须以相反的顺序阅读这些函数

public static void demoRecursion( int n, int depth ) {

    if ( n <= 0 ) {
        return;
    }

    System.out.println( "Before recursive call, depth " + depth );

    demoRecursion( n - 1, depth + 1 );

    System.out.println( "After recursive call, depth " + depth );

}
关于您的打印以便调试。“here1”的大量出现是由于您在函数输出之前打印了它。这就是为什么你在这里有很多东西。然后,每个函数调用都打印输出

最后,关于最后一个条件:

 if(newa.length!=0)
当a为[81]时,newa将是长度为0的数组,这是为了确保不能打印长度为0的数组。因此,直到最后一级,这个条件始终为真


请注意,将
打印(newa)
在这种情况下,删除检查
a
不是长度为0的数组的第一部分不会改变函数中的任何内容

基本上,该方法通过对连续元素求和来重复减小数组。例如:

4, 7, 3, 6, 7
|/ |/ |/ |/
11 10 9  13
|/ |/ |/
21 19 22
|/ |/
40 41
 |/
 81
它的工作方式是,每次调用时,它都会创建一个新数组,该数组的大小比newa小一个元素,并根据公式newa[i]=a[i]+a[i+1]计算每个元素newa[i]。显然,我们希望在某个时候停止,我们不希望继续递归并获得StackOverFlowException,所以当输入数组为空时停止。所以,在psuedo代码中,整个事情是

print(a):
    if a is empty
        escape from function
    else
       create newa array of length a.length-1
       newa[i] = a[i]+a[i+1] //fill the smaller array
       print(newa) // print the smaller array

通常,如果递归方法中存在打印,则递归调用之前的所有打印将按增加递归深度的顺序打印,递归调用之后的所有打印将按相反顺序打印

public static void demoRecursion( int n, int depth ) {

    if ( n <= 0 ) {
        return;
    }

    System.out.println( "Before recursive call, depth " + depth );

    demoRecursion( n - 1, depth + 1 );

    System.out.println( "After recursive call, depth " + depth );

}
所以这并不是说
a
的规模在增加。很简单,在深度1,你有一个5项数组,在深度2,你有一个4项数组,在深度3,你有3,依此类推

因此,由于我上面演示的反向打印效果,每个深度的数组都是在较深级别的数组之后打印的,较短


如果在递归调用之前打印了数组,则打印的顺序将是递减的。

您需要仔细思考才能正确理解它

既然你不明白newa的大小是如何减小的,我将解释这一部分。首先,从
main

调用
print
方法,然后,第一个
print
开始执行,并创建长度为4的
newa
并在
print(newa)
处停止,而第二个
print
开始执行。
然后,第二个
print
开始执行,创建长度为3的
newa
,并在
print(newa)
处停止,而第三个
print
开始执行。
然后,第三个
print
开始执行,创建长度为2的
newa
,并在
print(newa)
处停止,而第四个
print
开始执行。
然后,第四个
print
开始执行,创建长度为1的
newa
,并在
print(newa)
处停止,而第五个
print
开始执行。
然后,第5个
print
开始执行,并创建长度为0的
newa
并在
print(newa)
处停止,而第6个
print
开始执行。
然后,第6次
print
开始执行,并在
返回时停止此时长度为0。

第五次
打印继续进行,由于长度为0,因此不会打印任何内容。
第四个
打印
继续并打印
newa
(长度为1)
第三次
打印
继续并打印
newa
(长度为2)
第二次
打印
继续并打印
newa
(长度为3)
第一次
打印
继续打印
newa
(长度为4)


最后,
main
打印整个数组。

帮助您理解的是删除所有println语句和ins
public static void demoRecursion( int n, int depth ) {

    if ( n <= 0 ) {
        return;
    }

    System.out.println( "Before recursive call, depth " + depth );

    demoRecursion( n - 1, depth + 1 );

    System.out.println( "After recursive call, depth " + depth );

}