遞迴的應用場景和呼叫機制、遞迴需要遵守的重要規則

ningmengshuxiawo發表於2020-11-17

簡單地說: 遞迴就是方法自己呼叫自己,每次呼叫時傳入不同的變數.遞迴有助於程式設計者解決複雜的問題,同時可以讓程式碼變得簡潔

①通過列印問題回顧遞迴呼叫的機制

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)=1
2
3
4

遞迴需要遵守的重要規則

執行一個方法時,就建立一個新的受保護的獨立空間(棧空間)
方法的區域性變數是獨立的,不會相互影響, 比如n變數
如果方法中使用的是引用型別變數(比如陣列),就會共享該引用型別的資料(就是每一個新建的棧空間都指向同一個堆空間),如下圖
在這裡插入圖片描述

遞迴必須向退出遞迴的條件逼近,否則就是無限遞迴,出現StackOverflowError,死龜了:)
當一個方法執行完畢,或者遇到return,就會返回,遵守誰呼叫,就將結果返回給誰,同時當方法執行完畢或者返回時,該方法也就執行完畢。

相關文章