有人可以帮我理解递归吗?

时间:2013-12-10 16:58:11

标签: java recursion

所以我在课堂上复习,我似乎无法理解它。有什么建议可以帮助描绘这个过程吗?

从样本测试中我做:

class Q4
{
    public static void main(String[] args)
    {
        f(3);
    }
    public static void f(int x)
    {
        if (x > 0)
        {
            System.out.println(x);
            f(x-1);
            System.out.println(x);
            f(x-1);
        }
        System.out.println("bert");
    }
}

我看到输出但我不明白为什么它是输出。 谢谢

6 个答案:

答案 0 :(得分:4)

考虑递归的好方法是从基本情况开始,然后看看当您一次应用递归步骤时会发生什么。< / p>

基本情况:f(0)

此处的基本案例是x <= 0f(0)的输出是多少?我们可以直接看到这一点,因为永远不会输入if语句。基本案例输出是:

bert

递归步骤:f(1)

现在让我们看看f(1)会发生什么。当x为1时,代码会输入if语句并最终调用f(0)两次。如果在函数体中用1替换x,您将看到执行以下语句:

System.out.println(1);
f(0);
System.out.println(1);
f(0);
System.out.println("bert");

很明显println语句的作用是什么,但两个f(0)调用呢?好吧,我们知道f(0)打印了什么,因为我们已经分析了基本情况。 f(0)打印bert。所以上面这些行的输出是:

1       // System.out.println(1);
bert    // f(0);
1       // System.out.println(1);
bert    // f(0);
bert    // System.out.println("bert");

递归步骤:f(2)

如果您对f(2)应用相同的分析,您会看到它执行:

System.out.println(2);
f(1);
System.out.println(2);
f(1);
System.out.println("bert");

如果我们在调用f(1)的两个地方替换f(1)的输出,我们会得到:

2       // System.out.println(2);
1       // f(1);
bert
1
bert
bert
2       // System.out.println(2);
1       // f(1);
bert
1
bert
bert
bert    // System.out.println("bert");

递归步骤:f(3)

最后,f(3)执行:

System.out.println(3);
f(2);
System.out.println(3);
f(2);
System.out.println("bert");

代入f(2)的输出,我们得到:

3       // System.out.println(3);
2       // f(2);
1       
bert
1
bert
bert
2       
1       
bert
1
bert
bert
bert    
3       // System.out.println(3);
2       // f(2);
1       
bert
1
bert
bert
2       
1       
bert
1
bert
bert
bert    
bert    // System.out.println("bert");

答案 1 :(得分:2)

通过查看fx,我们可以看到f在这些情况下会做些什么。

f(3)表示:

System.out.println(3);
f(2);
System.out.println(3);
f(2);
System.out.println("bert");

f(2)表示:

System.out.println(2);
f(1);
System.out.println(2);
f(1);
System.out.println("bert");

f(1)表示:

System.out.println(1);
f(0);
System.out.println(1);
f(0);
System.out.println("bert");

f(0)表示:

System.out.println("bert");

因此,将所有内容放在一起意味着我们正在减少数字的交叉输出并"bert"。要查看每个数字或"bert"来自哪里,您需要逐步执行递归调用以查看正在发生的事情。

例如,您最后会在一行中以多个"bert"字符串结尾,但这是因为对f的每次调用都以打印"bert"结束。

答案 2 :(得分:0)

浏览纸上的代码。

f(3):
    "3"
    f(3-1) = f(2):
        "2"
         f(2-1) = f(1):
              "1"
              f(1-1) = f(0):
                   "bert"
              "1"
              f(1-1) = f(0):
                   "bert"
         f(2-1) = f(1):
              "1"
               //...

答案 3 :(得分:0)

每次调用f(x-1)时,都会创建f的新本地范围,并且仅在该本地范围内可以使用名为x的新本地变量:

调用f(3)会创建一个新的本地范围,其中局部变量x初始化为值3.让我们调用这个新的本地范围LS1。单步执行此方法,我们可以看到3 > 0为真,因此该方法打印出3(首次调用System.out(x)

然后该方法调用自身,但传递的值为x-1。 JVM在这里做的第一件事是计算x-1,即2。注意它没有将结果赋给x;我们称之为x的范围中的变量LS1仍为3.

它的作用是调用f(2)。这将创建一个带有名为x的局部变量的新本地范围。让我们调用这个新的本地范围LS2。在LS2中,我们无法从LS1访问任何变量。 LS2有自己的一组局部变量 - 为LS2分配的内存中的新块与LS1的不同。 LS2中的局部变量x现在初始化为值。

同样,我们现在可以逐步完成f以跟进流程。系统打印出2,然后计算x-1(等于1)并调用f(1)。同样,在调用f(1)时,会创建一个新的本地范围(让我们称之为LS3),并为其局部变量分配另一个新的内存块。

LS3中x的值初始化为1,方法继续。它打印出1,然后调用f(0)。这将创建一个新的局部作用域(让我们称之为LS4),并为其局部变量分配一个新的内存块。 x中的LS4初始化为0.单步执行f,我们发现0 > 0为false,因此会忽略代码块。打印出bert并退出该方法。

现在销毁本地作用域LS4并将其内存块(包含其本地变量)释放回堆中。控制现已回落到我们称之为LS3的局部范围。回顾过去,我们可以看到x中变量LS3的最后一个值是1.下一条说明打印出来,因此打印出1,然后打印出来{{ 1}}然后退出方法。

退出现在会破坏我们称之为bert的本地范围。控制流回退到我们称为LS3的本地范围。 LS2中的变量x设置为LS2,因此会打印2,然后是2

方法退出,销毁bert并退回LS2LS1中的xLS1,因此会打印3,然后是3。方法退出,程序结束。

希望一切都有意义!

修改

对不起,我错过了对bert的第二次打电话,在那一刻,同样的事情再次发生了;创建一个新的范围并重复该方法。

答案 4 :(得分:-1)

请参阅Recursion是一种方法调用,其中同一方法调用自身 就像你的代码一样:

 public static void f(int x)
    {
        if (x > 0)
        {
            System.out.println(x);
            f(x-1);    //at this point it will call itself as f(2)
            System.out.println(x);
            f(x-1);
        }
        System.out.println("bert");
    }

它会继续调用自己,直到if条件为真。您需要了解的主要内容是方法调用的堆栈情况,无论它是否递归。

答案 5 :(得分:-1)

private String returnType(int t, String[] s) <- return type recursion example
{
    String arrayed = s[t];
    if (t == 0) // <--if 0
        return " " + arrayed;
    else
        return arrayed + returnType(t - 1, s); <--if != 0 return value and then call itself again with the value -1.
}

当它达到0时返回数组。这将通过String [] s,并将所有字符串并排放在一个字符串中