2017-04-06 42 views
1

我很久以前在類中寫了一個基本的遞歸問題,我試圖記住我如何獲得打印的輸出。Java遞歸輸出名稱向前和向後

它基本上打印出一個名稱向前和向後。我瞭解它如何向前打印名稱,但我對於如何向後打印名稱無能爲力。我做了一個調試,以逐步查看發生了什麼,但無法理解名稱向前打印後index如何減少。

public class CharRecursion 
{ 

public static void printName(String name, int index) 
    { 
    if(index > name.length() - 1) 
    { 
     return; 
    } 
    else 
    { 
     System.out.println(name.charAt(index)); 
     printName(name, index + 1); 
     System.out.println(name.charAt(index)); 
    } 
    } 
public static void main(String[] args) 
    { 
     printName("Brian", 0); 
    } 

} 

輸出是BriannairB

+0

看看第二個'System.out.println' - 它在遞歸達到結束後被調用。 –

+0

除了Jaroslaw的評論,請注意'index + 1'不會改變'index'的值。因此,在下一行中,打印相同的字符。 –

+0

謝謝。我明白第二個System.out.println是什麼導致它,但它是如何索引正在減少導致字母倒退?我必須錯過簡單的東西。 –

回答

2

向後部分來自第二System.out.println(name.charAt(index));聲明。

這一個只調用一次遞歸調用已經結束,遞歸,所以你最終與反向字符串,看看後綴標誌:

System.out.println(name.charAt(index) + " - "); 
    printName(name, index + 1); 
    System.out.println(name.charAt(index) + " * "); 

你得到:

B - 
r - 
i - 
a - 
n - 
n * 
a * 
i * 
r * 
B * 

由於實際的調用順序爲:

printName(name,0)> printName(name,1)> printName(name,2)> printName(name,3)> printName(name,4)

第一個電話解決您的第二println說明會printName(name, 4),然後printName(name, 3)等..和印刷的順序變爲:

System.out.println(name.charAt(4) + " * "); 
System.out.println(name.charAt(3) + " * "); 
System.out.println(name.charAt(2) + " * "); 
System.out.println(name.charAt(1) + " * "); 
System.out.println(name.charAt(0) + " * "); 
1

明白這一點的方式是通過其手動步驟,使用筆和紙。 我不能強烈推薦你實際上對這件事物理上用真正的紙片,直到你明白髮生了什麼。

用一張紙記錄輸出。

每次調用printName()時都使用一張新的單獨紙張。

main()開始。當您看到printName("Brian", 0)時,這是啓動新紙張的信號。在工作表頂部,寫入輸入:name - "Brian", index = 0

現在你在printName(),所以一步一步地通過它。 0小於"Brian".length() - 1,這樣你就可以跳到else塊:

  • System.out.println(name.charAt(index)); - 這麼寫的"Brian".charAt(0)結果在你的輸出表:B

  • printName(name, index + 1) -- since you're seeing printName()again, take another sheet of paper, write the inputs名稱= 「布賴恩」,索引= 1`在頂部,和地方此上與前一薄片的頂部。

繼續以這種方式工作,您將繼續添加到您的紙張堆。這與Java維護的執行堆棧直接類似;這是您在堆棧跟蹤中看到的相同堆棧。

最終你會達到index = "Brian".length() -1的點,所以你回來。當您看到return時,請取下正在使用的紙張,將其擰緊並將其投入垃圾箱。運行時已完成此方法的調用。繼續下面的表格,從中斷。你現在在第二個System.out.println(name.charAt(index));。所以把這個字符寫在輸出表上。

當你完成後,你會發現你在輸出表上寫了「BriannairB」,你應該對遞歸有更好的理解。

每張紙都代表堆棧幀。請記住:

  • 在執行期間的給定時刻,只有最上面的堆棧幀在執行過程中「可見」。
  • 局部變量和參數存儲在堆棧幀中。在執行的某個時刻,當前堆棧幀中index的值將爲3。這對下面堆棧幀中index的值沒有影響 - 這是一個完全獨立的存儲器,當3幀結束並彈出堆棧時仍將爲2

一旦你得到的這個竅門,但是,你可以看看它在更多的「聲明」的水平。​​是做什麼的?

它打印「B」,然後printName("Brian", 1),然後「B」。

我覺得這個實現稍微容易理解:

void printName(String s) { 
     if(s.length() > 0) { 
      System.out.println(s.charAt(0)); 
      printName(s.substring(1)); 
      System.out.println(s.charAt(0)); 
     } 
    } 

所以,printName("Brian")寫道B然後printName("rian")然後B

或者從最深去堆棧會:

printName("")沒有寫。

因此printName("n")寫入n然後printName("")然後n - 這是nn

+0

好!一旦你提到堆棧跟蹤,它開始點擊。所以基本上第二個println語句會通過堆棧返回,然後吐出接下來出現的任何內容,最終反向。如果我理解正確。 –

+0

@BrianHogans我認爲你的程序執行過程的心理模型有點偏離。 'println'語句不會「穿過」任何東西。 JVM按聲明逐個執行方法。當它遇到一個方法調用時,它將添加到堆棧中,並在處理該方法調用時將其他所有內容都保留。當它到達方法調用的結尾時,它將從堆棧中移除該項目並繼續執行。如果你遵循我的建議並在紙上「運行」,那麼你就是JVM。 – slim

+0

好的,我一定會那樣做的。我想確保在我轉向不同的東西之前,我在概念上得到這一點。 –

0

以下是程序的執行順序。程序以遞歸方式調用printName("Brian",index)函數,其在每次調用之前首先執行System.out.println(name.charAt(index));。當索引達到5函數調用開始返回時,第二個System.out.println(name.charAt(index));在每次返回後執行。