递归基础

时间:2019-02-07 09:44:09

标签: java if-statement recursion

我已经阅读了有关递归的内容,并且对理解我在阶乘中使用的非常基本的东西非常感兴趣。既然我对它进行了很好的研究,就看到了它的特定视频,但是以某种方式,这件事使我非常困惑。我可以选择编写代码并继续前进,但我会很好地学习。

以下是递归的来源:

我想问一件事,因为在代码中我看到了if-else这件事。我知道其他条件是否很好。但是在这里事情有点复杂。

public static int fact(int n){
  if(n <=1)
     return 1;
  else 
     return n * fact(n-1);
}

在上面的代码中,这里的结果似乎是正确的,但是我认为某种原因是为什么它在满足条件时不只返回1,以及如何打印正确的结果。有一个我无法掌握的陷阱。请帮助我解决这个问题。

考虑我是编码领域的学习者。谢谢

7 个答案:

答案 0 :(得分:4)

简单的空运行将带您找到答案。每次N减1直到达到1。

例如,假设N为4

它将进入else语句,它将变为extension UIButton { public func centerImageAndTextVertically(spacing: CGFloat) { layoutIfNeeded() let contentFrame = contentRect(forBounds: bounds) let imageFrame = imageRect(forContentRect: contentFrame) let imageLeftInset = bounds.size.width * 0.5 - imageFrame.size.width * 0.5 let imageTopInset = -(imageFrame.size.height + spacing * 0.5) let titleFrame = titleRect(forContentRect: contentFrame) let titleLeftInset = ((bounds.size.width - titleFrame.size.width) * 0.5) - imageFrame.size.width let titleTopInmset = titleFrame.size.height + spacing * 0.5 imageEdgeInsets = UIEdgeInsets(top: imageTopInset, left: imageLeftInset, bottom: 0, right: 0) titleEdgeInsets = UIEdgeInsets(top: titleTopInmset, left: titleLeftInset, bottom: 0, right: 0) } }

递归现在有return 4 * fact(4-1)

事实3会导致4 * fact(3)

第一个等式等于3 * fact (2);

它一直发生到N变成1,所以整个方程就像4 * 3 * fact(2)

从1开始递归停止,我们开始通过递归堆栈返回。

希望它可以澄清您的问题。

答案 1 :(得分:3)

将递归函数视为树可以使初学者更容易理解。每个递归函数都分两个步骤运行:

第1步:树扩展

第2步:反向替换

考虑下图。在图像中,红色显示步骤1,绿色显示步骤2。在步骤1终止之前,不能执行步骤2。这就是原因,否则,您需要在每个递归函数中都具有终止条件;树将继续扩展,程序将耗尽内存。

Tree showing a calculation of factorial of 4

调用fact(4)时,它扩展为4 * fact(3),如下所示:

fact(4) = 4 * fact(3)
fact(3) = 3 * fact(2)
fact(2) = 2 * fact(1)
fact(1) = 1

现在,您要做的就是将这些值替换为fact(4)的值。

在硬件上,递归功能像上面显示的树一样扩展。这发生在堆栈上,树的每个节点都是一个激活记录。请参阅对know more about activation record的回答。

答案 2 :(得分:2)

递归函数是自行调用

的函数

它允许程序员使用最少的代码来编写高效的程序。

缺点是,如果写得不正确,它们会导致无限循环和其他意外结果。

为了编写一个递归函数。

  1. 要考虑的第一点是何时应该决定退出循环,即if循环

  2. 第二个是如果我们是我们自己的职能部门,应该执行的程序

从给定的示例中:

public static int fact(int n){
  if(n <=1)
     return 1;
  else 
     return n * fact(n-1);
}

从上面的示例

if(n <=1)
     return 1;

是退出循环的决定因素

else 
     return n * fact(n-1);

是要完成的实际处理吗

为了便于理解,让我一步一步地完成任务。

让我们看看如果我运行fact(4)

会在内部发生什么
  1. 替换n = 4
public static int fact(4){
  if(4 <=1)
     return 1;
  else 
     return 4 * fact(4-1);
}

If循环失败,因此进入else循环 因此它返回4 * fact(3)

  1. 在堆栈内存中,我们有4 * fact(3)

    替换n = 3

public static int fact(3){
  if(3 <=1)
     return 1;
  else 
     return 3 * fact(3-1);
}

If循环失败,因此进入else循环

因此它返回3 * fact(2)

请记住,我们将其称为“''4 * fact(3)``

fact(3) = 3 * fact(2)

的输出

到目前为止,堆栈中有4 * fact(3) = 4 * 3 * fact(2)

  1. 在堆栈内存中,我们有4 * 3 * fact(2)

    替换n = 2

public static int fact(2){
  if(2 <=1)
     return 1;
  else 
     return 2 * fact(2-1);
}

If循环失败,因此进入else循环

因此它返回2 * fact(1)

请记住我们叫4 * 3 * fact(2)

fact(2) = 2 * fact(1)

的输出

到目前为止,堆栈中有4 * 3 * fact(2) = 4 * 3 * 2 * fact(1)

  1. 在堆栈内存中,我们有4 * 3 * 2 * fact(1)

    替换n = 1

public static int fact(1){
  if(1 <=1)
     return 1;
  else 
     return 1 * fact(1-1);
}

If循环为真

因此它返回1

请记住我们叫4 * 3 * 2 * fact(1)

fact(1) = 1

的输出

到目前为止,堆栈中有4 * 3 * 2 * fact(1) = 4 * 3 * 2 * 1

事实(4)= 4 * 3 * 2 * 1 = 24 的结果

答案 3 :(得分:1)

您好,其他代码学习者, 我希望StackOverflow上的人会宽恕您的问题,因为他们从未对我的问题有任何疑问。

无论如何,让我们遍历代码,看看到底发生了什么:

我会在我的主叫“事实(5)”。 以下是背景情况的代表:

public static int fact(5){
  if(5 <=1)
     return 1;
  else 
     return 5 * fact(4);
}

事实4将是:

public static int fact(4){
  if(4 <= 1)
     return 1;
  else 
     return 4 * fact(3);
}

以此类推:

public static int fact(3){
  if(3 <= 1)
     return 1;
  else 
     return 3 * fact(2);
}

public static int fact(2){
  if(2 <= 1)
     return 1;
  else 
     return 2 * fact(1);
}

public static int fact(1){
  if(1 <= 1) //true for the first time
     return 1;
  else 
     return 1 * fact(0);
}

在“事实(1)”中,if情况首次触发,并返回1。如果现在我们向上工作,则返回:

//fact(1) = 1
public static int fact(2){ //returns the else case, 2*1 = 2 so fact(2) = 2
  if(2 <= 1)
     return 1;
  else 
     return 2 * 1;
}

public static int fact(3){ //same here, fact(2) = 2, so we end up with 3*2 = 6
  if(3 <= 1)
     return 1;
  else 
     return 3 * 2;
}

public static int fact(4){
  if(4 <= 1)
     return 1;
  else 
     return 4 * 6; //fact(3) = 6, so we return 4*6 = 24
}

public static int fact(5){
  if(5 <= 1)
     return 1;
  else 
     return 5 * 24; //fact(4) = 24, so we return 5*24 = 120
}

我希望这有助于澄清您的问题。

答案 4 :(得分:1)

我认为最好的理解方法是举一个例子。例如,如果您调用fact(3),则代码执行将如下所示(作为伪代码):

事实(3)

3 is greater than 1 so
return 3 * fact(2)  ---> Lets wait for this

事实(2)

2 is greater than 1 so
return 2 * fact(1)  ---> Lets wait for this

事实(1)

1 is same as 1 so
return 1 ---> 1 will be the result of fact(1)

现在让我们回到事实(2)

return 2 * 1 --> 2 this will be the result of fact(2)

现在让我们回到事实(3)

return 3 * 2 ---> This give 6, and it is the final result of fact(3)

答案 5 :(得分:1)

递归用于将任务划分为类似的小任务时使用。并利用它来完成一项大型任务。像这种情况,数字阶乘可以表示为数字乘以(number-1)的阶乘,直到变为1。其中1和0的阶乘为1。

所以<= 1是一个例外情况,需要单独处理然后中断进一步的计算。

这就是if子句处理<= 1条件且else子句调用相同的事实方法来计算n-1阶乘的原因。查看下面代码中的注释。

public static int fact(int n) {
    if (n <= 1) {
        // if a number is 1 or less than on then factorial will be 1
        return 1;
    } 
    else {
        /*this part will execute only of number is greater than 1, ex 2,3
         * According to factorial logic, factorial of a number n will be (n * factorial of (n-1))
         * Ex: factorial of 2 = 2*1
         *  factorial of 3 = 3*2*1
         *  factorial of 4 = 4*3*2*1
        */
        return n * fact(n - 1);
    }
}

答案 6 :(得分:0)

好的, 假设您传递了3,现在第一次迭代正在等待函数调用的结果。现在,此呼叫触发另一个呼叫,并等待故障转移。最终,当它为1时,返回1,并且该呼叫具有答案,因此它会增加并发送故障回复。因此,return最终到达正在等待的第一个呼叫,并返回最终答案。最简单的方法是您打电话给一个人(a),那个人叫另一个人(b),那个人叫另一个(c),对方给了他答复。现在,当c提供答复时,b处理该答复并将其提供给a,而后者又处理该答复并将其还给您。这就是为什么您在递归程序中得到正确答案而不是1的原因。 希望你能理解。

谢谢 Vino V