递归在 C# 中的工作原理

本文关键字:工作 递归 | 更新日期: 2023-09-27 17:56:48

这是我的代码

using System;
public class Program
{
   public static void Method(int flowerInVase)
      {
         if (flowerInVase > 0)
         {
             Method(flowerInVase - 1);
             Console.WriteLine(flowerInVase);
         }
      }
   public static void Main()
   {
      Method(3);
   }
}

我对方法调用本身Console.WriteLine(flowerInVase);行感兴趣,直到它被条件终止。只有在堆栈已满之后,它才会从上面弹出每个方法,控制台从最小值 1,2,3 开始写入数字。

为什么console.writeline仅在堆栈弹出时才起作用,为什么它不写方法终止的方式上的数字,例如 3,2,1?编译器仅在完成递归时才使用 writeline。

递归在 C# 中的工作原理

调用的结构如下所示。 也许这个可视化会帮助你理解为什么数字打印 1、2、3 而不是 3、2、1:

Method(3);
  flowerInVase > 0 ?
  Yes - Method(2);
    flowerInVase > 0 ?
    Yes - Method(1);
      flowerInVase > 0 ?
      Yes - Method(0);
        flowerInVase > 0 ?
        No
      WriteLine(1);
    WriteLine(2);
  WriteLine(3);

原因是因为您对Method(flowerInVase - 1)的调用是在WriteLine(flowerInVase)的调用之前进行的。执行在有机会打印其所在的数字之前跳转到该方法的其他副本。

由于

if语句中的行的排序方式,您得到 1,2,3

Main()Method(3).
Method(3)在有机会打印"3"之前调用Method(2)。 执行立即跳到Method的顶部;您第一次调用 Method 时,使用 flowersinvase=3 ,直到递归调用完成才会完成。 同样,Method(2)立即呼叫Method(1)Method(1)呼叫Method(0)

Method(0)什么都不做,回到Method(1),正是它停止的地方;下一行是你的WriteLine调用,它打印"1"然后返回,它会拾取呼叫到Method(2)它停止的地方,打印"2",依此类推"3"。

仅当您调用的方法在跳转到它们以递归方式调用的任何方法之前运行完成时,才会得到"3,2,1",这不是 C# 的工作方式。 关于方法调用,你必须记住的是,一旦你调用了一个方法,执行就会立即跳转到你调用的方法的开头;方法调用后的代码在方法返回之前不会执行。

因为它这样做:

flowerInVase = 3
call Method(3)
    call Method(2)
        call Method(1)
        WriteLine(1)
    WriteLine(2)
WriteLine(3)

则输出为:

1
2
3

如果反转线条:

    Console.WriteLine(flowerInVase);
    Method(flowerInVase - 1);

它将首先打印,然后递归,因此它将打印 3、2、1。

编译器仅在完成递归时才使用 writeline。

这样做是因为你告诉它这样做。在您的代码中,首先执行递归(调用 Method() ),只有当递归完成后,您才写入数字。

如果你想先写数字,在执行递归之前,你需要在代码中切换语句:

public static void Method(int flowerInVase)
{
   if (flowerInVase > 0)
   {
       Console.WriteLine(flowerInVase);
       Method(flowerInVase - 1);
   }
}
为什么

控制台.writeline仅在卡住弹出时才有效,为什么它不是 在方法走向终止的方式上写下数字,例如 3,2,1?

因为你的Method(flowerInVase - 1);是在Console.WriteLine(flowerInVase);之前调用的。

如果您逐行执行代码,这是有道理的。如果你分解它,它真正说的是你总是在你有机会向控制台写入任何东西之前创建一个递归调用的新实例。只有在创建了允许的所有调用(if语句失败)后,线程的控制才会返回到现有方法。

Create method -> check parameter 
  -> create method - > check parameter
    -> create method -> check parameter
      etc. etc.
    -> print value
  -> print value
-> print value

所以现在你看到它正在恢复控制,就像它被调用的方式一样。最后一个调用的函数需要先完成其操作,然后调用它的函数才能完成。

也许你应该研究递归是什么意思。 这是一个非常简单的递归方法示例:即调用自身的方法。 递归在许多领域都有很多用途,尤其是编程,但这不是你问的,也不是我要回答的。

如果您逐行阅读代码,您将看到调用Method(3),进而调用 Method(2) ,最重要的是,它在输出值 3 之前进行此调用。 因此,Method(2)将在输出 Method(3) 的最后一行之前完整执行。 同样,Method(2)在输出 2 之前调用自身,因此整个Method(1)将在此之前执行。

一个简单的流程图:

Main() -> Method(3)               
              --->calls Method(2)
                            --->calls Method(1)
                                          -Method(0) not viable
                                          -if statement failed
                                          -Outputs '1'
                            -Outputs '2'
              -Outputs '3'
End of Main()