2016-02-26 100 views
1

我已經完成了HTML,但是這與現在在我的AP類中學習java毫無關係。所以我幾乎是全新的編碼。今天我們學習了遞歸,並且我非常肯定我在使用它的時候能夠理解它,就像在這個視頻中一樣。有人可以解釋這個代碼中的遞歸

https://www.youtube.com/watch?v=fpuWkZs51aM

但後來我們不得不以不同的方式來使用它。我們需要製作一個名爲WordPlay的程序,一次接受任何單詞,直到輸入「停止」字樣。當停止放入時,以相反的順序打印出來。這是代碼。

import java.util.Scanner; 

public class HelloWorld 
{ 
    public static void main(String[] args) 
    { 

     System.out.println("Enter list of words, one per line"); 
     System.out.println("Final word should be STOP"); 
     wordList(); 
    } 
    public static void wordList() 
    { 
     Scanner keyboard = new Scanner(System.in); 

     String word = keyboard.next(); 
     if (word.equalsIgnoreCase("STOP")) 
      System.out.println(); 
     else 
      wordList(); 
     System.out.println(word); 
    } 
} 

所以,我不明白的是,這工作得很好,但是當我看到的wordList()結束它在我看來,它只是不斷重複的最後一個字,這是輸入。我沒有得到我想念的東西。有人可以在這裏解釋邏輯嗎?

回答

0

遞歸does輸出是輸入的字,但是每次調用wordList獲得命名word本地變量(每個word值是「the stack」)。如果標記爲final,則不會有任何抱怨 - 因爲word未在初始化後修改。此外,你應該提取Scanner(每個調用也創建一個新的本地的)。

public static void wordList() 
{ 
    Scanner keyboard = new Scanner(System.in); 

    final String word = keyboard.next(); // <-- this is the current word. 
    if (word.equalsIgnoreCase("STOP")) 
     System.out.println(); 
    else 
     wordList(); // <-- it's not STOP, recurse... which 
        //  will get a new local word (and print it). 
    System.out.println(word); // <-- however, this is still current word. 
} 
+0

好的。所以,如果我理解這個權利,那麼當它得到STOP時,它會自動打印它,並將「word」=留給前一個字符串,然後當打印該字符串時,它會在該字符串之前設置「word」=等等,直到它打印所有值? 這是我不理解的部分,一旦打印出STOP並且最後一個字符串「word」有什麼可以使堆棧的其餘部分打印出來? – JustABitSalty

+0

@JustABitSalty它打印出' word',注意'new String(「a」)!= new String(「a」)''很重要,在這個意義上'word'的值永遠不會改變。每個調用都有自己的* local *變量。 –

+0

好的,我現在和你一起解釋,另一篇文章解釋操作的順序,至於移動掃描儀到別的地方,會在實際的程序中引起內存問題嗎?我記得我們的老師告訴我們堆棧存儲在內存中。 – JustABitSalty

0

功能將從頂部執行至底部如常,但如果它進入else塊它將跳回開頭如下所示。它將「迴路」正是這樣,直到word等於「STOP」,那麼它會如果塊輸入,打印出一個新行(System.out.println()),然後跳過else塊,打印出word然後退出功能。 if-else語句中的括號將使這更容易看到。

public static void wordList() 
{ 
    |->Scanner keyboard = new Scanner(System.in); 
    | 
    | String word = keyboard.next(); 
    | if (word.equalsIgnoreCase("STOP")) { 
    | System.out.println(); 
    | } 
    | else { 
    |---wordList(); 
    } 
    System.out.println(word); 
} 
0

它基本上是一個遞歸函數或一次又一次地調用自身,直到如果它裏面的條件是假的方法。 因此,這裏首先由用戶輸入的新詞存儲在名爲word的變量中,然後if condition將檢查存儲在word中的值是否爲Stop,如果不是,則再次調用wordlist方法並且再次重複上述所有過程。 因此每次輸入新值都存儲在word變量中。 這就是全部!

0
public static int wordList() 
{ 
    Scanner keyboard = new Scanner(System.in); 

    String word = keyboard.next(); 
    if (word.equalsIgnoreCase("STOP")) 
    { 
     System.out.println(); 
     return 0; 
    } 
    System.out.println(word); 
    return wordList(); 
} 

試試這個

0

這將是操作的局部變量字序列

1)調用的詞表()
2)獲取一個字,說WORD1和商店。
3)在遞歸調用wordlist之前,WORD1進入堆棧。堆疊就像一個盒子,你可以把餅乾放在另一個餅乾上,然後你可以取出最後放置的餅乾。現在堆棧有WORD1
4)換一個單詞,說WORD2並存儲在局部變量字中。這是一個新的函數調用,即使它是遞歸的。所以一個新的局部變量字被分配內存。
5)在遞歸調用wordlist之前,WORD2進入堆棧。所以現在WORD2將成爲第一個,而WORD1將會在堆棧下面。
5)得到另一份工作,現在是停止。
6)停止打印
7)函數返回 8)現在流程返回到前一個調用。現在WORD2彈出堆棧,因爲包含WORD2的局部變量屬於遞歸調用的這個實例。
8)打印WORD2並返回上一個呼叫。現在WORD1彈出堆棧,因爲本地變量存儲WORD1屬於遞歸調用的這個實例。
9)打印WORD1。

只是想告訴你一個類比,讓我們假設你有一個類似的任務。除了你以外,你還得從一位朋友那裏得到一套書。只要他給你一本名爲「停止」的書,你就必須按照相反的順序讓他回來。

1)你從他那裏拿書
2)獲得下一本書之前,你把它放在一個表,因爲你不能保持這一點,從您的朋友
3獲得更多的書籍),但獲得下從他那裏預訂
4)在獲得下一本書之前,你把它保留在第一本書上
5)你繼續這樣做,直到你得到一本書名爲stop
6)現在你開始退還書籍,首先你會返回這本書名叫停止,隨着你的繼續,因爲書被堆放,你將以相反的順序將書歸還。

希望澄清。

0

如果行System.out.println(word)位於if語句之前,它只會重複輸入最後一個字。

要理解遞歸,您需要「堆棧」的概念。對wordList()的每個調用發生在堆棧中的單獨級別。在每個堆棧級別中有一個不同的word變量。由於``System.out.println(word)`行是在遞歸調用後發生的,所以這些行都在解壓堆棧時(即在上一級​​返回之後)執行。這就是爲什麼詞語以相反的順序出現。圖像:如果你把一個箱子堆在另一個箱子上面,當你拆箱時,最後一個箱子是第一個出箱(因此縮寫LIFO = Last In First Out)。

遞歸的另一個重要概念是有一種方法來阻止它(即阻止無限遞歸)。在這個程序中,當用戶輸入「STOP」時完成。

0

我喜歡將這些問題看作是「調用堆棧」。每次「遞歸調用」該方法時,都會添加另一個「堆棧」。每個遞歸方法都需要一個停止的情況。在你的問題中,第一次出現「停止」(如何方便)這個詞是你停止的情況。 例如,如果有人進入:一旦出現單詞「STOP」

「狐」 「熊」 「鹿」 「STOP」

,它將被打印。現在我們拿起我們在您的「調用棧」,這是

詞表()的結尾離開

現在唯一的一步左邊是

的System.out.println(字)

字「鹿鼎記」將被打印出來,現在正在打印我們的名單是:

「STOP」 「鹿鼎記」

如此反覆UNT我們達到最後的話。