簡體   English   中英

有人可以幫我理解遞歸嗎?

[英]Can someone help me understand recursion?

所以我在課堂上復習,我似乎無法理解它。 有什么建議來幫助描繪這個過程嗎?

從樣本測試我做:

class Q4
{
    public static void main(String[] args)
    {
        f(3);
    }
    public static void f(int x)
    {
        if (x > 0)
        {
            System.out.println(x);
            f(x-1);
            System.out.println(x);
            f(x-1);
        }
        System.out.println("bert");
    }
}

我看到輸出,但我不明白為什么它是輸出。 謝謝

考慮遞歸的一個好方法是從基本情況開始,然后看看當您一次一步應用遞歸步驟時會發生什么。

基本情況:f(0)

這里的基本情況是x <= 0 f(0)的輸出是多少? 我們可以直接看到它,因為永遠不會輸入if語句。 基本案例輸出是:

bert

遞歸步驟:f(1)

現在讓我們看看f(1)會發生什么。 x為1時,代碼進入if語句並最終調用f(0)兩次。 如果在函數體中用1替換x ,則會看到執行以下語句:

System.out.println(1);
f(0);
System.out.println(1);
f(0);
System.out.println("bert");

很明顯println語句的作用是什么,但兩個f(0)調用呢? 好吧,我們知道f(0)打印是什么,因為我們已經分析了基本情況。 f(0)打印bert 所以上面這些行的輸出是:

1       // System.out.println(1);
bert    // f(0);
1       // System.out.println(1);
bert    // f(0);
bert    // System.out.println("bert");

遞歸步驟:f(2)

如果對f(2)應用相同的分析,您將看到它執行:

System.out.println(2);
f(1);
System.out.println(2);
f(1);
System.out.println("bert");

如果我們在調用f(1)的兩個地方用f(1)的輸出替換,我們得到:

2       // System.out.println(2);
1       // f(1);
bert
1
bert
bert
2       // System.out.println(2);
1       // f(1);
bert
1
bert
bert
bert    // System.out.println("bert");

遞歸步驟:f(3)

最后, f(3)執行:

System.out.println(3);
f(2);
System.out.println(3);
f(2);
System.out.println("bert");

f(2)的輸出代替,我們得到:

3       // System.out.println(3);
2       // f(2);
1       
bert
1
bert
bert
2       
1       
bert
1
bert
bert
bert    
3       // System.out.println(3);
2       // f(2);
1       
bert
1
bert
bert
2       
1       
bert
1
bert
bert
bert    
bert    // System.out.println("bert");

通過查看fx我們可以看到f在這些情況下會做什么。

f(3)表示:

System.out.println(3);
f(2);
System.out.println(3);
f(2);
System.out.println("bert");

f(2)表示:

System.out.println(2);
f(1);
System.out.println(2);
f(1);
System.out.println("bert");

f(1)表示:

System.out.println(1);
f(0);
System.out.println(1);
f(0);
System.out.println("bert");

f(0)表示:

System.out.println("bert");

因此,將所有內容放在一起意味着我們將數字的交叉輸出遞減並且"bert" 要查看每個數字或"bert"來自哪里,您需要逐步執行遞歸調用以查看正在發生的事情。

例如,你最后會在一行中以幾個"bert"字符串結束,但那是因為每次調用f以打印"bert"結束。

瀏覽紙上的代碼。

f(3):
    "3"
    f(3-1) = f(2):
        "2"
         f(2-1) = f(1):
              "1"
              f(1-1) = f(0):
                   "bert"
              "1"
              f(1-1) = f(0):
                   "bert"
         f(2-1) = f(1):
              "1"
               //...

每次調用f(x-1) ,都會創建f的新本地范圍,並且只有在該局部范圍內才能使用名為x的新局部變量:

調用f(3)創建一個新的局部作用域,其中局部變量x初始化為值3.讓我們調用這個新的局部作用域LS1 單步執行此方法,我們可以看到3 > 0為真,因此該方法打印出3 (首次調用System.out(x)

然后該方法調用自身,但傳遞值x-1。 JVM在這里做的第一件事是計算x-1,即2. 它注意它沒有將結果賦給x ; 我們稱之為LS1的范圍中的變量x仍為3。

它的作用是調用f(2)。 這將創建一個帶有名為x的局部變量的新本地范圍。 讓我們稱這個新的本地范圍LS2 在LS2中,我們無法從LS1訪問任何變量。 LS2有自己的一組局部變量 - 為LS2分配的內存中的新塊與LS1的不同。 LS2中的局部變量x現在初始化為值2。

同樣,我們現在可以通過f來跟隨流程。 系統打印出2 ,然后計算x-1 (等於1),它調用f(1) 同樣,在調用f(1)會創建一個新的局部作用域(讓我們稱之為LS3 ),並為其局部變量分配另一個新的內存塊。

LS3中x的值初始化為1,方法繼續。 它打印出1,然后調用f(0) 這將創建一個新的本地范圍(讓我們稱之為LS4 ),並為其局部變量分配一個新的內存塊。 LS4 x初始化為0.通過f ,我們發現0 > 0為假,因此忽略代碼塊。 bert打印出來,方法退出。

現在銷毀本地范圍LS4並將其內存塊(包含其本地變量)解除分配回堆。 控制現已回落到我們稱為LS3的局部范圍。 回顧過去,我們可以看到LS3中變量x的最后一個值是1.下一條指令說打印出來,所以打印1 ,然后打印出bert然后退出方法。

退出現在破壞了我們稱為LS3的本地范圍。 控制流回落到我們稱為LS2的本地范圍。 LS2的變量x設置為2 ,因此打印2 ,然后是bert

方法退出,破壞LS2並回退到LS1 LS1 x3 ,因此打印3 ,然后是bert 方法退出,程序結束。

希望一切都有道理!

編輯

對不起,我基本上錯過了對f(x-1)的第二次調用,此時同樣的事情又發生了; 創建一個新范圍並重復該方法。

請參閱Recursion是一種方法調用,其中同一方法調用自身。
就像你的代碼一樣:

 public static void f(int x)
    {
        if (x > 0)
        {
            System.out.println(x);
            f(x-1);    //at this point it will call itself as f(2)
            System.out.println(x);
            f(x-1);
        }
        System.out.println("bert");
    }

它將繼續調用自己,直到if條件為真。 您需要了解的主要事情是方法調用的Stack情況 ,無論它是否是遞歸的。

private String returnType(int t, String[] s) <- return type recursion example
{
    String arrayed = s[t];
    if (t == 0) // <--if 0
        return " " + arrayed;
    else
        return arrayed + returnType(t - 1, s); <--if != 0 return value and then call itself again with the value -1.
}

當它達到0時返回陣列。這將通過String [] s,並將所有字符串並排放在一個字符串中

暫無
暫無

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

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