[英]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");
}
}
我看到輸出,但我不明白為什么它是輸出。 謝謝
考慮遞歸的一個好方法是從基本情況開始,然后看看當您一次一步地應用遞歸步驟時會發生什么。
這里的基本情況是x <= 0
。 f(0)
的輸出是多少? 我們可以直接看到它,因為永遠不會輸入if
語句。 基本案例輸出是:
bert
現在讓我們看看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)
應用相同的分析,您將看到它執行:
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)
執行:
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");
通過查看f
和x
我們可以看到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
x
為3
,因此打印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.