遞迴的應用場景和呼叫機制、遞迴需要遵守的重要規則
簡單地說: 遞迴就是方法自己呼叫自己,每次呼叫時傳入不同的變數.遞迴有助於程式設計者解決複雜的問題,同時可以讓程式碼變得簡潔
①通過列印問題回顧遞迴呼叫的機制
public class recursion {
public static void main(String[] args) {
test(4);
}
public static void test(int n) {
if (n > 2) {
test(n - 1);
}
System.out.println("n=" + n);
}
}
結果
n=2
n=3
n=4
分析:當程式執行到主方法時,首先在棧裡面開闢一個獨立的空間,這個空間其實是一個棧,從資料結構來講,底層編譯原理用的是棧,首先呼叫了test(4),根據遞迴的呼叫規則,它會立即開闢一個新棧,此時n=4,n>2,呼叫test(3),又會開闢一個新棧,呼叫test(2),又會開闢一個新棧,n不大於2,
test(2)
{
if(n>2)
{
test(1)
}
System.out.println("n=" + 2);
此時在控制檯輸出2。
那麼棧頂執行完畢,退出棧,執行棧中下一個元素,就是test(3),程式碼如下
test(3)
{
if(n>2)
{
test(2)
}
System.out.println("n=" + 3);
因為程式是自頂向下執行的,test(3)中會執行test(2)以及System.out.println(“n=” + 3);
所以test(3)中的test(2)執行完輸出2後,執行test(3)中的System.out.println(“n=” + 3);此時在控制檯輸出3。
test(3)出棧,執行test(4),test(4)的程式碼如下
test(4)
{
if(n>2)
{
test(3)
}
System.out.println("n=" + 4);
test(4)中會執行test(3)和 System.out.println(“n=” + 4),所以test(3)執行完之後,控制檯輸出4.
總結
這個程式碼的執行過程大概就是如下圖
test(4)呼叫test(3)後輸出4,test(3)呼叫test(2)後輸出3,test(2)執行直接輸出2,呼叫順序是①②③,執行順序是③②①
如果還不懂的話我們們這樣看
test(4)執行test(3)再執行System.out.println(“n=” + 4);但是是先執行test(3)的所有分支再執行System.out.println(“n=” + 4);如下圖所示,test(3)的所有分支包括test(2)和System.out.println(“n=” +3);
那麼需要先執行test(2)的所有分支再執行System.out.println(“n=” +3);
因為2不大於2,所以test(2)只執行System.out.println(“n=” +2);
所以輸出順序如下圖所示
這就好比你吃完飯之後要做作業,但是完成吃飯這件事情還需要買菜和做飯,所以分解下來就是,買菜做飯、寫作業。
test(4)
{
if(n>2)
{
test(3)
{
if(n>2)
{
test(2)
{
if(n>2)
{
test(1);
}
System.out.println("n=" + 2);
}
}
System.out.println("n=" + 3);
}
}
System.out.println("n=" + 4);
}
遞迴呼叫的規則:
1:當程式執行到一個方法時,就會開闢一個獨立的空間(在棧區)
2:每個空間的資料(區域性變數)是獨立的
如果更改程式碼,加上else
public class recursion {
public static void main(String[] args) {
test(4);
}
public static void test(int n) {
if (n > 2) {
test(n - 1);
}
else {
System.out.println("n=" + n);
}
}
}
輸出結果只有2,因為進入if的就不會進入else進行輸出了,只有test(2)不滿足n>2,所以只會輸出2
n=2
②通過階乘問題回顧遞迴呼叫的機制
public class recursion {
public static void main(String[] args) {
int res=factorial(4);
System.out.println("res=" + res);
}
public static int factorial(int n){
if(n==1)
{
return 1;
}
else
{
return factorial(n-1)*n;
}
}
}
結果
res=24
執行過程分析
factorial(4)=factorial(3)4;
factorial(3)=factorial(2)3;
factorial(2)=factorial(1)2;
factorial(1)=1;
所以factorial(4)=1234
遞迴需要遵守的重要規則
執行一個方法時,就建立一個新的受保護的獨立空間(棧空間)
方法的區域性變數是獨立的,不會相互影響, 比如n變數
如果方法中使用的是引用型別變數(比如陣列),就會共享該引用型別的資料(就是每一個新建的棧空間都指向同一個堆空間),如下圖
遞迴必須向退出遞迴的條件逼近,否則就是無限遞迴,出現StackOverflowError,死龜了:)
當一個方法執行完畢,或者遇到return,就會返回,遵守誰呼叫,就將結果返回給誰,同時當方法執行完畢或者返回時,該方法也就執行完畢。
相關文章
- 遞回應用場景和呼叫機制以及問題和規則
- 【小白學演算法】10.遞迴的呼叫機制、使用時要注意的規則演算法遞迴
- 遞迴呼叫 VS 迴圈呼叫遞迴
- 遞迴和尾遞迴遞迴
- 尾呼叫和尾遞迴遞迴
- 什麼是遞迴?遞迴和迴圈的異同遞迴
- python-動態規劃的遞迴、非遞迴實現Python動態規劃遞迴
- 遞迴優化:尾呼叫和Memoization遞迴優化
- 舉例說明你對尾遞迴的理解,有哪些應用場景遞迴
- 什麼是遞迴呼叫遞迴
- 遞迴尾呼叫優化遞迴優化
- 遞迴實現原則遞迴
- 遞迴的列印和階乘運用遞迴
- Vue3.0的遞迴監聽和非遞迴監聽Vue遞迴
- 遞迴、分治和動態規劃遞迴動態規劃
- 快速排序【遞迴】【非遞迴】排序遞迴
- 遞迴和遞推總結遞迴
- 遞迴和非遞迴分別實現求n的階乘遞迴
- 用 JavaScript 的方式理解遞迴JavaScript遞迴
- JavaScript和ABAP的尾遞迴JavaScript遞迴
- Android遍歷所有控制元件的遞迴和非遞迴實現Android控制元件遞迴
- 遞迴遞迴
- ?30 秒瞭解尾遞迴和尾遞迴優化遞迴優化
- Oracle和Mysql遞迴OracleMySql遞迴
- 徹底理解遞迴,從遞迴的本質說起!遞迴
- [20180531]函式呼叫與遞迴.txt函式遞迴
- 二分法的簡單實現——-遞迴和非遞迴遞迴
- JavaScript中的遞迴JavaScript遞迴
- 函式的遞迴函式遞迴
- 目標和——遞迴的實踐遞迴
- 揹包問題的遞迴與非遞迴演算法遞迴演算法
- 二叉樹的前中後序遍歷(遞迴和非遞迴版本)二叉樹遞迴
- go 遞迴Go遞迴
- JavaScript遞迴JavaScript遞迴
- 分而治之-遞迴遞迴
- 理解遞迴遞迴
- 漢諾塔和遞迴遞迴
- PHP 樹-不需要遞迴的實現方法PHP遞迴