简体   繁体   English

如何理解java中递归的概念?

[英]How to understand the concept of recursion in java?

I'm new to java programming, and our teacher taught us the concept of recursion and I found it to be a bit complicated.我是java编程的新手,我们的老师教了我们递归的概念,我发现它有点复杂。 All I understood that it works like a loop(like the factorial of 4) but I still don't quite get it why it works like that.我只知道它像一个循环一样工作(就像 4 的阶乘),但我仍然不太明白为什么它会这样工作。 Can I get a detailed explanation on this topic?我可以获得有关此主题的详细说明吗? Here is the piece of code and a picture my teacher used to explain.这是我老师用来解释的一段代码和一张图片。

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));
    }
}

In the following image, the blue color represents stack winding, and the green is stack unwinding, and again I don't know what stack winding and unwinding is.下图中,蓝色代表stackwinding,绿色是stack unwinding,再次不知道stackwinding和unwinding是什么。

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

When a call is made to another method, a stack frame is created to hold the state of the current method and it is pushed onto the stack.当调用另一个方法时,会创建一个堆栈帧来保存当前方法的状态并将其压入堆栈。 This is regardless of a method calling itself or another method.这与调用自身或其他方法的方法无关。

When the call returns, the stack frame is popped of the stack, the state of the method is restored and execution continues in the calling method.当调用返回时,栈帧从栈中弹出,方法的状态被恢复并在调用方法中继续执行。

Recursion is when a method (directly or indirectly) calls itself.递归是指方法(直接或间接)调用自身。 The general form of a recursive method is:递归方法的一般形式是:

  • If a parameter meets a terminating condition, return (usually a result)如果参数满足终止条件,则返回(通常是结果)
  • Else adjust parameters for the next iteration and call self否则为下一次迭代调整参数并调用 self

The code your teacher wrote has some style issues.你老师写的代码有一些风格问题。 It would be clearer if written like this:如果这样写就更清楚了:

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

Eradicating the unnecessary variable t and redundant else (there is no "else" when the "if" returns - there is merely continuation of execution)消除不必要的变量t和多余的else (当“if”返回时没有“else”——只有继续执行)

I would write it like this, eliminating the if altogether:我会这样写,完全消除if

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

A recursive function is a function that calls itself until it reaches a return statement, that stops it from recalling itself.递归函数是一个调用自身直到到达返回语句的函数,该语句阻止它调用自身。 Take your example, the Factorial function.以您的示例,阶乘函数。 Factorial is a mathematical function that returns the number multiplied by itself - 1 multiplied by itself - 2, ... multiplied by 1, example: factorial of 5 = 5!阶乘是一个数学函数,它返回乘以自身的数字 - 1 乘以自身 - 2,... 乘以 1,例如:5 = 5 的阶乘! = 5x4x3x2x1 = 120. it is also equal to itself multiplied by the factorial of itself -1, which is: 5! = 5x4x3x2x1 = 120。它也等于自身乘以自身的阶乘-1,即:5! = 5x4! = 5x4! Take into consideration that 0!考虑到 0! = 1. to represent this in a Java code, you need a loop that multiplies the numbers starting from 1, and going till the number you are calculating its factorial. = 1. 要在 Java 代码中表示这一点,您需要一个循环,将数字相乘,从 1 开始,一直到要计算其阶乘的数字。 Further more, explaining your code, let us calculate Factorial(5): Factorial() returns an integer.此外,解释您的代码,让我们计算 Factorial(5): Factorial() 返回一个整数。

Initial Call from main(): 5 != 0, then skip the condition (n == 0);来自 main() 的初始调用:5 != 0,然后跳过条件 (n == 0); t = Factorial(5-1) = Factorial(4); t = 因子(5-1) = 因子(4);

Second call from Factorial(4): 4 != 0, then skip the condition (n == 0);来自 Factorial(4) 的第二次调用:4 != 0,然后跳过条件 (n == 0); t = Factorial(4-1) = Factorial(3); t = 因子(4-1) = 因子(3);

Third call from Factorial(3): 3 != 0, then skip the condition (n == 0);来自 Factorial(3) 的第三次调用:3 != 0,然后跳过条件 (n == 0); t = Factorial(3-1) = Factorial(2); t = 因子(3-1) = 因子(2);

Fourth call from Factorial(2): 2 != 0, then skip the condition (n == 0);来自 Factorial(2) 的第四次调用:2 != 0,然后跳过条件 (n == 0); t = Factorial(2-1) = Factorial(1); t = 因子(2-1) = 因子(1);

Fifth call from Factorial(1): 1 != 0, then skip the condition (n == 0);来自 Factorial(1) 的第五次调用:1 != 0,然后跳过条件 (n == 0); t = Factorial(1-1) = Factorial(0); t = 因子(1-1)= 因子(0);

Sixth call from Factorial(0): 0 == 0, then return value 1;来自 Factorial(0) 的第六次调用:0 == 0,然后返回值 1;

First return, 1, to Fifth call (Factorial(1)): return n*t = return 1*1 = return value 1;第一次返回,1,到第五次调用(Factorial(1)): return n*t = return 1*1 = return value 1;

Second return, 1, to Fourth call (Factorial(2)): return n*t = return 2*1 = return value 2;第二次返回,1,到第四次调用(Factorial(2)): return n*t = return 2*1 = return value 2;

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

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

Second return, 24, to First call (Factorial(5)): return n*t = return 5*24 = return value 120;第二次返回,24,到第一次调用(Factorial(5)): return n*t = return 5*24 = return value 120;

Second return, 120, to Initial call (from main()): print(120);第二次返回,120,到初始调用(来自 main()):print(120);

Hope this helps you understand recursion.希望这可以帮助您理解递归。

When one knows that a task can be broken into similar smaller tasks ,then we use recursion or calling the same method(until we met a certain condition).当我们知道一个任务可以分解成类似的小任务时,我们就使用递归或调用相同的方法(直到满足某个条件)。 Recursion not only helps in execution of a problem without having to define or invoke another method,it also helps in visualizing a pattern by which the task is getting executed Recursion不仅有助于在无需定义或调用其他方法的情况下执行问题,还有助于可视化执行任务的模式

Personally, I do not like the factorial problem.就个人而言,我不喜欢阶乘问题。 I find it hard to understand and I do not think it explains recursion in a clear way.我觉得很难理解,而且我认为它没有以清晰的方式解释递归。 So lets look at a different example.所以让我们看一个不同的例子。 Lets say that we want to print numbers from 1-100.假设我们要打印 1-100 之间的数字。 This is a very simple task with a for loop and a counter, but it can also be done with recursion.这是一个非常简单的任务,有一个 for 循环和一个计数器,但也可以用递归来完成。 For example:例如:

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);
}

When a function is called, that call goes on top of the stack.当一个函数被调用时,该调用进入堆栈顶部。 Think of this like a stack of cards.把这想象成一堆卡片。 Each one has a number on it (1-100).每一个上面都有一个数字(1-100)。 When a function calls itself, a new card gets added to the stack.当一个函数调用自身时,一张新卡片被添加到堆栈中。 When the function finishes, it is taken off of the stack.当函数完成时,它被从堆栈中取出。

So for the example above, every time numbersAscending is called, it prints out the current value for x before calling that function again.因此,对于上面的示例,每次调用 numbersAscending 时,它都会在再次调用该函数之前打印出 x 的当前值。 This results in the numbers being printed in order from 1-100.这将导致按 1-100 的顺序打印数字。 As soon as 100 is reached, it stops calling itself and pops each function off of the stack.一旦达到 100,它就会停止调用自己并将每个函数从堆栈中弹出。

On the other hand, every time numbersDescending is called, it calls itself again before printing out the number.另一方面,每次调用 numbersDescending 时,它都会在打印数字之前再次调用自己。 In this way, x doesn't start printing until it reaches 100. It then moves back down the stack, printing each number as it goes back to the main method.这样,x 直到达到 100 才会开始打印。然后它向下移回堆栈,在返回到 main 方法时打印每个数字。

/*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");
}
}

I am not sure if it explains, but if you had a precalculus class then you should know that factorial can be defined in two waqys.我不确定它是否解释了,但是如果您有微积分预科课程,那么您应该知道阶乘可以在两个 waqy 中定义。

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

of we define我们定义

1!=1 1!=1

and

n!=n*(n-1)! n!=n*(n-1)!

Try to see yourself that those definitions are equivalent.试着自己看看这些定义是等价的。 Pick let us say, 5!选择让我们说,5!

according to second definition根据第二个定义

5!=5*4! 5!=5*4!

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

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

and so on.等等。 Keep doing it until you hit 1!.继续这样做,直到你击中 1!。 But 1!=1 so you stop.但是 1!=1 所以你停止了。

Recursion in programming is the same thing.编程中的递归是一回事。

TomW汤姆

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM