【问题标题】:Binary trees, returning the next node in a preorder traversal二叉树,在前序遍历中返回下一个节点
【发布时间】:2013-03-04 16:58:03
【问题描述】:

我有一个任务,我需要一些方法方面的帮助。

所以我有一棵这样的树:

                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 之后的节点),我不应该得到下一个节点吗?

【问题讨论】:

  • 可以修改函数签名吗?处理root 比处理tvprev 要容易得多。这是因为树的每个孩子本身也是一棵树。
  • 什么意思? t 是我可以传入的树的根。
  • 你应该持有递归的方法,而不是再次将之前访问过的信息传递给方法;此信息已经在堆栈中。我将发布一个答案来解释我的前序遍历方法。

标签: java binary-tree preorder


【解决方案1】:

我不确定递归执行该任务是否那么容易。

使用堆栈以迭代方式解决任务可能是一种更好的方法:

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;
}

此方法未经测试,但应该可以工作。

【讨论】:

  • 您不应在最后一个 if 语句中使用身份运算符 ==,而应使用 equals()
【解决方案2】:

这是一个如何递归完成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 都会发生变化。试着用贯穿的方式形象化,你就会理解这个概念。
  3. 您在开头缺少对空节点的检查(尤其是t)。

您可以继续根据此调整结果。

最后一点是关于这种方法的运行时复杂性,我强烈建议您了解递归函数的运行时复杂性。它将在未来对您有很大帮助。检查this wikipedia article 的重复关系。

【讨论】:

  • 我可以看到你在做什么。我正在返回一个节点,因为要获取节点的下一个节点,所以前序遍历中 K 的下一个节点是 I.. 你在我之前帖子的评论中说我的节点将被保存在堆栈中.. .那么当我访问它并获得J之后的下一个节点时,我怎样才能获得J?
  • K 的下一个节点将是I,具有递归的控制流。我的意思是,在您处理完K(打印出来,对其进行一些操作等)之后,该方法将返回到上一个调用,并将当前的root 设置为I(在您的情况下为@ 987654334@ 将是I 我相信)。这些将由堆栈自动处理,您不必担心。请查看 Stack 以及它如何与递归一起使用,您就会明白这一点。
  • 我了解堆栈如何与递归调用一起工作。可以说我只是要遍历树的左侧。 - 首先检查 A 是否有左,它对它进行递归调用 - 然后检查 b 是否有左,它对它进行递归调用 - 然后检查 D 有一个左,它对其进行递归调用 - 然后检查H 有一个left,它对它进行递归调用
  • - 然后检查 J 有左,它不会从递归调用中返回 - 现在检查 H 是否有右,它有,现在我们可以从该递归调用返回 - 现在检查是否 D有一个权利,它有——现在我们可以,如果我有一个左边,它没有,然后检查它是否有一个权利——它没有——然后我们检查 B 是否有一个权利,它有。我看不出我怎么能从 K 到 I...我的逻辑在这里是正确的,是吗?
  • @miniJavaLearner 我一直非常忙,无法快速回复,对此深表歉意。如果你在这里创建一个聊天室,我们可以讨论这个问题(我不想继续发很多cmets,谢谢)。
【解决方案3】:

我提供了一个运行时间为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;
    }
}

【讨论】:

  • 这是否在每次调用前序遍历时返回不同的节点,正确的节点?这实际上是相当惊人的。
猜你喜欢
  • 2021-03-08
  • 1970-01-01
  • 2023-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多