2013-03-04 76 views
0

我有一個任務,我需要一些方法的幫助。二叉樹,返回預先遍歷中的下一個節點

所以我有這樣的樹:

   A 
      / \ 
      B  C 
     / \/ \ 
      D E F  G 
     / \ 
     H  I 
    / \ 
    J  K 

,我的方法是:

public BinaryTree preorderNext(BinaryTree t, BinaryTree v, BinaryTree prev) {  

    prev = t; 

    if(t.getLeft() != null) { 
     preorderNext(t.getLeft(), v, prev); 
    } 

    if(t.getRight() != null) { 
     preorderNext(t.getRight(), v, prev); 
    } 


    if(prev == v) { 
     return t; 
    } 

    return null; 
} 

講師給了一個簡單的實現樹。這個類被稱爲BinaryTree,如果你想建立一個到它的節點鏈接,那麼你可以指定左邊和右邊的BinaryTree節點是什麼。

一個節點有兩個鏈接(一個到左邊,另一個到右邊的孩子),沒有鏈接到頭部。

因此,使用當前的方法,我能夠成功地進行預遍歷,我通過編寫存儲在節點的元素的打印語句來測試。

但是當我運行測試時,它告訴我A的下一個前序節點是B,K的下一個前序節點會拋出一個空異常,但它應該是I?

任何想法,我哪裏去錯了?變量prev應該保存對訪問的最後一個節點的引用,所以如果它等於節點v(這是我指定的節點,在v之後返回節點),我不應該得到下一個節點嗎?

+1

你能修改函數簽名嗎?處理'root'比't','v'和'prev'要容易得多。這是因爲樹的每個孩子本身也是一棵樹。 – arin 2013-03-04 17:09:02

+0

你是什麼意思? t是我可以通過的樹的根。 – tenkii 2013-03-04 17:12:06

+0

您應該持有遞歸方法,而不是將先前訪問過的信息再次傳遞給該方法;這些信息已經在堆棧中。我將發佈一個答案來解釋我的前序遍歷的方法。 – arin 2013-03-04 17:16:06

回答

0

這裏是preorder traversal遞歸完成的實現。

public void preOrderTraversal(BinaryTree root){ 
    if(root == null) return; 

    System.out.println(root); 
    preOrderTraversal(root.getLeft()); 
    preOrderTraversal(root.getRight()); 
} 

注:

  1. 我不知道你的做法;你爲什麼要返回一個節點?在任何情況下,當root爲空時,您可以返回「emptyNode」並通過if語句處理它。
  2. 正如你所看到的,我只處理root,任何級別的root變化。試着用一個run-through來想象這個,你會理解這個概念。
  3. 您在開始時缺少對空節點的檢查(特別是對於t)。

您可以繼續調整您的結果。

最後要說的是這種方法的運行時複雜性,我強烈建議理解遞歸函數的運行時複雜性。它將在未來幫助你很多。檢查this wikipedia article重現關係。

+0

我可以看到你正在嘗試做什麼。 我正在返回一個節點,因爲要獲得節點的下一個節點,所以在預遍序列中K的下一個節點是I .. 您在我以前的文章的評論中說我的節點將保存在堆棧...所以我如何獲得J當我點擊它並獲得J後的下一個節點? – tenkii 2013-03-04 17:37:18

+0

'K'的下一個節點將是遞歸控制流的'I'。我的意思是,在處理完'K'後(打印出來,對其進行一些操作等),該方法將返回到先前的調用,並將當前的'root'作爲'I'(在您的情況下,我會相信)。這些將由堆棧自動處理,您不必擔心這一點。請查看Stack以及它如何與遞歸一起使用,並且您將理解這一點。 – arin 2013-03-04 17:47:41

+0

我明白堆棧如何與遞歸調用一起工作。 可以說我只是要遍歷樹的左側。 - 首先檢查A是否有一個左邊,它是這樣遞歸調用它 - 然後檢查是否有一個左邊,它這樣做遞歸調用它 - 然後檢查D有一個左邊,它這樣做遞歸調用它 - 然後檢查H有一個左邊,它這樣遞歸調用它 – tenkii 2013-03-04 18:21:35

0

我不確定遞歸執行該任務是否容易。

解決任務使用堆棧可能是一個更好的方法迭代方式:

public BinaryTree preOrderNext(BinaryTree toSearch) { 

    Stack<BinaryTree> openList = new Stack<BinaryTree>(); 

    openList.push(root); 

    while (openList.empty() == false) { 
     BinaryTree curr = openList.pop(); 

     if (curr.getRight() != null) 
      openList.push(curr.getRight()); 

     if (curr.getLeft() != null) 
      openList.push(curr.getLeft()); 

     if (curr.equals(toSearch) && openList.empty() == false){ 
      return openList.pop(); 
     } 
    } 
    return null; 
} 

,此方法是測試,但應該工作。

+0

在上一個if語句中,不應該使用標識符運算符==,而應該使用equals()。 – arin 2013-03-04 18:00:12

+0

你是對的。修復。 – trylimits 2013-03-04 18:02:27

0

我提供了一個運行在O(h)運行時間的答案。

class Node { 
    public int key; 
    public Node l; 
    public Node r; 
    public Node p; 

    public Node(int key) { 
     this.key = key; 
     this.l = null; 
     this.r = null; 
     this.p = null; 
    } 
} 

public Node preorderNext(Node v) { 
    if (v.l != null) { 
     return v.l; 
    } else if (v.r != null) { 
     return v.r; 
    } else { 
     while (v.p != null) { 
      if (v == v.p.l) { 
       if (v.p.r != null) { 
        return v.p.r; 
       } else { 
        v = v.p; 
       } 
      } else { 
       if (v.p.p == null) { 
        return null; 
       } else if (v.p == v.p.p.l) { 
        if (v.p.p.r != null) { 
         return v.p.p.r; 
        } else { 
         v = v.p; 
        } 
       } else { 
        v = v.p; 
       } 
      } 
     } 
     return null; 
    } 
} 
+0

這是否會在每次調用預定單遍歷時返回不同的節點,即正確的節點?那實際上非常驚人。 – 2017-06-01 20:30:23