簡體   English   中英

這段代碼如何在編譯器中執行?

[英]how this code execute in compiler?

我是 Java 新手,正在閱讀有關它的幾本書。 我無法弄清楚這段代碼的輸出是如何產生的:

import java.util.*;

class myclass {
    public static void main(String[] args) {
        Scanner myScanner = new Scanner(System.in);
        System.out.println(factorial(myScanner.nextInt())+"\n");
    }

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

任何人都可以為我一步一步地解釋這個嗎? 我了解主要方法和Scanner類,但我不明白當我在輸入處輸入一個像8這樣的整數時,我在輸出處得到40320

函數factorial使用遞歸來求解階乘。 這意味着該函數多次調用自身,直到 n 變為 0(其中它返回 1)。

因此,對於 n = 3,程序首先將結果設置為

Factorial(3) = factorial(2) * 3,
Factorial(2) = factorial(1) * 2,
Factorial(1) = factorial(0) * 1,
Factorial(0) = 1 (Because of the *if-statement*)

現在您可以將這些東西加在一起,因為它知道 Factorial(0)、Factorial(1)、Factorial(2) 和 Factorial(3) 是什么。

然后變成:

Factorial(0) = 1,
Factorial(1) = 1 * 1 = 1,
Factorial(2) = 1 * 2 = 2,
Factorial(3) = 2 * 3 = 6

首先:階乘函數

我想你不了解遞歸階乘函數。

函數聲明:

public static int factorial(int n){

0 的階乘是 1(例外):

if(n==0){
    return 1;
}

如果用戶介紹的數字不為 0,則:

    else { 
        int recurse = factorial(n-1);
        int result = recurse*n;
        return result;
   }
  1. 在這種情況下,例如使用recurse = factorial(2-1)調用函數,等待直到對函數的調用結束(在這種情況下調用的是同一個函數,但它不是問題,只需等待直到函數調用結束)。 因此調用階乘(2-1)。 未完待續...

  2. factorial(1), n==0 false ,因此進入 else 語句。 調用階乘(1-1)。 再等一次,直到函數 factorial(1-1) 結束。 未完待續...

  3. factorial(0), n==0 true ,因此return 1 對函數的調用結束,現在我們將繼續第 2 步。

  4. 在步驟 2 中繼續 factorial(1): factorial(1-1) 返回 1 並將其存儲在recurse int result = recurse * n所以結果 = 1·1。 最后在這一步返回result (1)。 現在我們轉到第 1 步,該步驟仍在 factorial(1) 調用中等待。

  5. 在步驟 1 中繼續 factorial(2): factorial(2-1) 返回 1 並將其存儲在recurse int result = recurse * n所以結果 = 1·2。 並返回result (2)。

最后 factorial(2) 返回 2. 想想 factorial(3), 4, 5, 6, 7, 最后你就會明白 factorial 8. 最重要的是,當你在你所在的地方調用同一個函數時,它將狀態保存在堆棧中並等待它完成。

當您正確格式化代碼時,代碼更容易處理,所以請在將來這樣做。 有時,當您使代碼更簡潔時,代碼也更容易處理。 請注意,您可以“內聯” result變量:

public static int factorial(int n) {

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

或者更簡單:

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

現在讓我們嘗試一些值。 讓我們嘗試使用“0”的值:

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

好的,沒錯:0! = 1。

讓我們嘗試使用“1”的值:

public static int factorial(int n) {
    if (n == 0) { 
        return 1; //not reached
    }
    return n * factorial(n-1); //<-- 1 * factorial(0) = 1 * 1 = 1
}

好:1! = 1。

讓我們嘗試使用“8”的值:

public static int factorial(int n) {
    if (n == 0) { 
        return 1; //not reached
    }
    return n * factorial(n-1); //<-- 8 * factorial(8-1) = 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 = 40320
}

這是有道理的,因為 8! = 40,320。

這樣做的方式稱為遞歸,因為該方法本質上是在調用自身。 如果做得好,遞歸是編程的一個美麗部分,因為代碼通常相當簡潔,並且是一種“分而治之”的心態。 這是編程中的一個介紹性概念。

一個好的程序員總是會考慮價值體系。 因此,在這種情況下,例如,如果 n 為 -1,您的函數將提供StackOverFlow錯誤。 (您可以將代碼更改為讀取if (n <= 1) )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM