2010-01-11 99 views
3

我對下面的代碼問題的Java return語句

private void printTree(Node node){ 
    if(node==null) return; 
    printTree(node.left); 
    System.out.print(node.data+" "); 
    printTree(node.right); 
} 

我真的不明白的點「回報;」在那裏陳述。它看起來像節點爲空,代碼不返回任何內容。但是如果沒有這一行,編譯器會產生一個異常錯誤。

回答

16

這是一個遞歸函數(反覆調用自己的函數)。 return的目的是爲了確保它不會永遠這樣做,因爲您在樹的底部運行時會導致空指針異常。

會發生什麼情況是,您第一次用一個節點(通常,但並非總是根節點)調用此函數時,它將首先打印該節點的左子樹,然後節點本身,然後是該節點的右側子樹。

打印出子樹的方式是使用該子樹的頂層節點調用自身。這是優雅地處理遞歸結構的一種非常普通的方法。

null的測試是這樣的,它有一個條件,當它到達一個沒有孩子在你正在檢查的特定面(左邊或右邊)的節點時,停止搜索樹的層級。

舉例來說,假設你有下面的樹(大寫字母與他們的數字與數字真正的節點是它們的價值,並===標記爲空值):

   A26    Level 0 
       | 
     +------+------+ 
     |    | 
     B14   C84   Level 1 
     |    | 
    +--+--+  +--+--+ 
    |  |  |  | 
    D11 ===  === E99  Level 2 
    |     | 
+--+--+    +--+--+ 
|  |    |  | 
=== ===   === === Level 3 

這裏會發生什麼,當你用A調用函數。

You call the function (level 0) with A. 
    The function will call itself (level 1) with B (A left). 
    The function will call itself (level 2) with D (B left). 
     The function will call itself (level 3) with null (D left). 
     The function will return to level 2. 
     The function will print out 11 from D. 
     The function will call itself (level 3) with null (D right). 
     The function will return to level 2. 
     The function will return to level 1. 
    The function will print out 14 from B. 
    The function will call itself (level 2) with null (B right). 
     The function will return to level 1. 
    The function will return to level 0. 
    The function will print out 26 from A. 
    The function will call itself (level 1) with C (A right). 
    The function will call itself (level 2) with null (C left). 
     The function will return to level 1. 
    The function will print out 84 from C. 
    The function will call itself (level 2) with E (C right). 
     The function will call itself (level 3) with null (E left). 
     The function will return to level 2. 
     The function will print out 99 from E. 
     The function will call itself (level 3) with null (E right). 
     The function will return to level 2. 
     The function will return to level 1. 
    The function will return to level 0. 
    The function will return to you. 

其結果是,它打印出的序列DBACE,其在排序的樹中,是按排序順序(11, 14, 26, 84, 99)的元素。


或者一個簡單的版本,如果你不能打擾通過我上面大量的解釋爲:

   A26    Level 0 
       | 
     +------+------+ 
     |    | 
     B14   ===   Level 1 
     | 
    +--+--+ 
    |  | 
    === ===     Level 2 

You call the function (level 0) with A. 
    The function will call itself (level 1) with B (A left). 
    The function will call itself (level 2) with null (B left). 
     The function will return to level 1. 
    The function will print out 14 from B. 
    The function will call itself (level 2) with null (B right). 
     The function will return to level 1. 
    The function will return to level 0. 
    The function will print out 26 from A. 
    The function will call itself (level 1) with null (A right). 
    The function will return to level 0. 
    The function will return to you. 

在這種情況下,你會得到BA(14,26)

+2

或者在下一行生成空指針異常。 – Don 2010-01-11 05:03:59

+0

好點,@Don,你幾乎肯定會在堆棧溢出之前得到一個空指針異常(除非你的堆棧特別小)。修改來修復。 – paxdiablo 2010-01-11 05:54:11

+0

對於一個全面的,很好解釋的答案+1。 – Matt 2010-01-11 10:27:14

4

聲明爲void的任何方法都不會返回值。它不需要包含返回語句,但它可能會這樣做。在這樣的情況下,返回語句可用於分支出來的控制流程塊的和退出的方法和簡單地使用這樣的:

return; 

從Java LangSpec:

14.17返回聲明

返回語句返回控制到 方法(§8.4,§15.12) 或構造函數(§8.8,§15.9)的調用者。

ReturnStatement: 
     return Expressionopt ; 

沒有表達 return語句必須包含在該被宣佈爲 方法的主體,採用 關鍵字void,不返回 (8.4節),或者在身體的任何值一個 構造函數(§8.8)。如果返回語句 出現在實例初始化程序 或靜態初始化程序(第8.7節)中,則會發生編譯時 錯誤。 A 返回語句不帶表達式 嘗試將控制權轉移給該方法的調用者或包含它的構造函數 。確切地說,沒有表達式 的 返回語句總是突然完成,原因 是沒有值的返回。

與表達 的return語句必須在一個方法包含在該被聲明爲返回 (8.4節)或編譯時錯誤 發生值 聲明。表達式必須表示某種類型T的變量或值,或發生編譯時錯誤。 T 類型必須是可分配的(第5.2節) 聲明的結果類型的方法,或者 發生編譯時錯誤。

0

在我看來,如果你的節點是null,它會在拋出NullReferenceException之前離開函數調用。因爲它是遞歸的,所以它需要通過向其父節點「退出」來處理樹的節點(樹葉)。

+0

是編譯器是否給出錯誤,或者你是否在運行時得到錯誤? – 2010-01-11 05:03:01

+0

當然,在運行時。 – 2010-01-11 05:03:49

0

你也有回報,所以你不要調用node.data。請記住,如果它爲null,則無法在其上調用實例方法。

0

'return'語句在這裏作爲遞歸調用的終止條件。每個遞歸方法都需要一個臨時終止條件,否則它會進入無限循環。

if(node==null) return; 

此聲明基本上表示您已到達葉節點(分支的最後一個節點)並終止光標的任何進一步移動。

,你得到的回報除去例外情況是由於這樣的事實,你沒有任何進一步的節點移動到一旦你已經達到了葉節點和聲明printTree(node.left); & printTree(node.right);無效。

0

一個不太令人困惑的方式來寫,這將是:

private void printTree(Node node){ 
    if (node.left != null) { 
     printTree(node.left); 
    } 
    System.out.print(node.data); 
    if (node.right != null) { 
     System.out.print(" "); 
     printTree(node.right); 
    } 
} 
+3

對我來說,問題中提出的版本看起來更清晰,因爲遞歸終止條件顯而易見。 – sateesh 2010-01-11 05:49:32

+1

這取決於你的編碼風格。擁有多於一個的回報通常會導致閱讀困難。不是每個人都會同意。 – fastcodejava 2010-01-11 06:36:18

+1

這兩個似乎都是順序遍歷二叉樹的明確實現:http://en.wikipedia.org/wiki/Tree_traversal – trashgod 2010-01-11 06:39:45

0

它有時很難辨認回報,這不是結尾。大多數人習慣於在這裏找到它。此外,沒有任何回報的回報也可能令人困惑。一個更明顯的寫法是:

 
private void printTree(Node node) { 
    if(node!=null) { 
     printTree(node.left); 
     System.out.print(node.data+" "); 
     printTree(node.right); 
    } 
} 

所以,簡單地說,「如果有節點,請訪問它」!

0

返回語句是簡單的在下面的方式來理解:

方法沒有返回類型不能返回值,但返回的控制。

任何可以返回值的方法都可以返回必須與返回方法類型兼容的值。