2013-03-04 87 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