【问题标题】:How to understand the concept of recursion in java?如何理解java中递归的概念?
【发布时间】:2020-07-27 11:39:47
【问题描述】:

我是 Java 编程新手,我们的老师教给我们递归的概念,我发现它有点复杂。我只知道它像循环一样工作(如 4 的阶乘),但我仍然不太明白为什么它会这样工作。我能得到关于这个话题的详细解释吗?这是我老师用来解释的一段代码和一张图片。

package javaapplication1;

public class JavaApplication1 {

static int factorial(int n){
    int t;
    if(n == 0){
        return 1;
    } else {
        t = factorial(n - 1);
        return n * t;
    }
}
public static void main(String[] args) {
    System.out.println(factorial(5));
    }
}

在下图中,蓝色代表堆栈卷绕,绿色代表堆栈展开,我也不知道什么是堆栈卷绕和展开。

http://i.stack.imgur.com/pjqJy.png

【问题讨论】:

  • 递归 - 一个(最终)再次调用自身的函数调用。 Winding = 再次调用自身,unwinding = 从之前的递归调用返回。
  • 在 Eclipse 等 IDE 中调试该程序,您可以按照详细流程进行操作。
  • Understanding recursion 的可能副本,尽管第一个答案开头有点幽默,但确实有一些实际内容。

标签: java recursion concept


【解决方案1】:

递归函数是一个在到达返回语句之前调用自身的函数,该语句阻止它调用自身。以你的例子,阶乘函数。 阶乘是一个数学函数,它返回与自身相乘的数字 - 1 与自身相乘 - 2, ... 乘以 1,例如:5 = 5 的阶乘! = 5x4x3x2x1 = 120。 它也等于自身乘以自身的阶乘-1,即:5! = 5x4! 考虑到 0! = 1。 要在 Java 代码中表示这一点,您需要一个循环,它将从 1 开始的数字相乘,直到您计算其阶乘的数字。 此外,解释您的代码,让我们计算 Factorial(5): Factorial() 返回一个整数。

来自 main() 的初始调用:5 != 0,然后跳过条件 (n == 0);吨 = 阶乘(5-1) = 阶乘(4);

Factorial(4) 的第二次调用:4 != 0,然后跳过条件 (n == 0); t = 阶乘(4-1) = 阶乘(3);

来自 Factorial(3) 的第三次调用:3 != 0,然后跳过条件 (n == 0); t = 阶乘(3-1) = 阶乘(2);

Factorial(2) 的第四次调用:2 != 0,然后跳过条件 (n == 0); t = 阶乘(2-1) = 阶乘(1);

来自 Factorial(1) 的第五次调用:1 != 0,然后跳过条件 (n == 0); t = 阶乘(1-1) = 阶乘(0);

来自 Factorial(0) 的第六次调用:0 == 0,然后返回值 1;

第一次返回,1,到第五次调用 (Factorial(1)):return n*t = return 1*1 = 返回值 1;

第二次返回,1,到第四次调用 (Factorial(2)):return n*t = return 2*1 = 返回值 2;

第三次返回,2,到第三次调用 (Factorial(3)):return n*t = return 3*2 = 返回值 6;

第二次返回,6,到第二次调用 (Factorial(4)):return n*t = return 4*6 = 返回值 24;

第二次返回,24,第一次调用 (Factorial(5)):return n*t = return 5*24 = 返回值 120;

第二次返回,120,初始调用(来自 main()):print(120);

希望这可以帮助您理解递归。

【讨论】:

  • 那么每个递归函数都有类似的逻辑吗?
  • 这是一个基本示例,它解释了递归背后的过程,是的。递归也是使用二叉树时的一个主要功能,例如搜索或基于逻辑插入值(知道在哪里插入值,左或右,检查每个节点......
【解决方案2】:

当调用另一个方法时,会创建一个堆栈帧来保存当前方法的状态并将其压入堆栈。这与调用自身的方法或其他方法无关。

当调用返回时,栈帧从栈中弹出,方法的状态被恢复并在调用方法中继续执行。

递归是指方法(直接或间接)调用自身。递归方法的一般形式是:

  • 如果参数满足终止条件,则返回(通常是结果)
  • 否则为下一次迭代调整参数并调用 self

你老师写的代码有一些风格问题。如果这样写会更清楚:

static int factorial(int n) {
    if (n == 0) {
        return 1;
    } 
    return n * factorial(n - 1);
}

消除不必要的变量t和多余的else(当“if”返回时没有“else” - 只是继续执行)

我会这样写,完全消除if

static int factorial(int n) {
    return n == 0 ? 1 : n * factorial(n - 1);
}

【讨论】:

  • 因此,如果我有多个条件,而不是使用 if,else if{}...else{},我只使用 ":" 和 :?: 在每个条件之后,直到我剩下没有其他选择?
  • @Frosty 三元运算符必须谨慎使用:嵌套条件通常会失去很多可读性。
【解决方案3】:

当我们知道一个任务可以分解成类似的更小的任务时,我们使用递归或调用相同的方法(直到我们满足某个条件)。Recursion不仅有助于执行问题而无需定义或调用其他方法,它还有助于可视化执行任务的模式

【讨论】:

  • 我如何确定,在哪些情况下我使用递归函数,我是否构造一个?
  • 如果你发现你的函数可以分解成更小的相同函数,但复杂度会降低。例如,要找到 n 的阶乘,你需要 (n-1)!*n 和 (n-1 )!可以使用 (n-2) 计算!以此类推。所以你会发现定义单个函数并用更小的参数调用它更容易,因此你应该使用递归
【解决方案4】:

就个人而言,我不喜欢阶乘问题。我觉得很难理解,我认为它不能清楚地解释递归。所以让我们看一个不同的例子。假设我们要打印 1-100 的数字。这是一个非常简单的任务,带有一个 for 循环和一个计数器,但也可以通过递归来完成。例如:

public static void main(String[] args) {
    numbersAscending(1);
    numbersDescending(1);   
}
//Prints 1 2 3 ... 100
public void numbersAscending(int x){
    System.out.println(x);
    if(x < 100){
        numbersAscending(x+1);
    }
}
//Prints 100 99 98 ... 1
public void numbersDescending(int x){
    if(x < 100){
        numbersDescending(x+1);
    }
    System.out.println(x);
}

当一个函数被调用时,该调用会在堆栈顶部进行。把它想象成一堆卡片。每个都有一个数字(1-100)。当一个函数调用自己时,一个新的卡片被添加到堆栈中。当函数完成时,它会从堆栈中取出。

因此对于上面的示例,每次调用 numbersAscending 时,它都会在再次调用该函数之前打印出 x 的当前值。这将导致按 1-100 的顺序打印数字。一旦达到 100,它就会停止调用自身并将每个函数从堆栈中弹出。

另一方面,每次调用 numbersDescending 时,它都会在打印出数字之前再次调用自己。这样,x 直到达到 100 才开始打印。然后它向下移回堆栈,在返回到 main 方法时打印每个数字。

【讨论】:

    【解决方案5】:
    /*This program in java will help you to understand all the basics of 
      recursion:
      ->how control flows in recursion
      ->how return is executed in the recursive functions
      ->how and when the statements after recursive function area executed.*/
    
    public class Understanding_Rec{
    
    public static int rec(int x)
    {
        if(x<5)
        {
            System.out.println("-->Smaller than 5");
            rec(x+1);
            System.out.println("<--After recursion inside x<5");
            return x;
        }
        else if(x<7)
        {
            System.out.println("-->Smaller than 7");
            rec(x+1);
            System.out.println("<--After recursion inside x<7");
        }
        System.out.println("<--No Condition Statement");
        return x;
    }
    
    public static void main(String[] args)
    {
        int x=1;
        rec(x);
        System.out.print(x+"Inside main");
    }
    }
    

    【讨论】:

      【解决方案6】:

      我不确定它是否解释,但如果你有一个初等课程,那么你应该知道阶乘可以在两个 waqy 中定义。

      n!=1*2*...*n

      我们定义的

      1!=1

      n!=n*(n-1)!

      试着让自己看看这些定义是等价的。选择让我们说,5!

      根据第二个定义

      5!=5*4!

      但是 4!=4*3!所以 5!=5*4*3!

      但是 3!=3*2!所以 5!=5*4*3*2!

      等等。继续这样做,直到你达到 1!。但是 1!=1 所以你停下来。

      编程中的递归也是一样的。

      TomW

      【讨论】:

        猜你喜欢
        • 2016-07-17
        • 2014-12-23
        • 1970-01-01
        • 2019-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多