【问题标题】:Recursive Tree Traversal Method With Return Type Array具有返回类型数组的递归树遍历方法
【发布时间】:2013-06-04 11:33:29
【问题描述】:

有没有办法递归地遍历树并返回一个范围为该递归方法的数组?

所以我最近回答了别人关于这个话题的问题。这个问题可以在这里找到:SO Question。我的解决方案使用了递归范围之外的数组,因此该方法不能(或至少可能不应该)返回该数组。但是,有没有办法编写一个遍历树的递归方法,使其返回一个数组?即使编写一个调用递归方法的初始方法也可以,但我想不出一个好的方法。

这是我之前建议的代码:

private List nodeValues = new ArrayList();

public void traversePreRecursive(BinarySearchTreeNode node) 
{
    if (node != null)
    {
        nodeValues.add(node.getValue());
        traversePreRecursive(node.getLeft());
        traversePreRecursive(node.getRight());
    }
}

如您所见,ArrayList 超出了递归的范围 - 因此返回它没有多大意义。有没有更好的方法来做到这一点?

【问题讨论】:

  • 这个问题最好有java标签
  • 已添加。不确定这是帮助还是阻碍,许多语言可能存在类似问题。

标签: java arrays recursion binary-tree traversal


【解决方案1】:
public static List traversePreRecursive(Node node) {
    if (node == null) return new ArrayList();

    List nodeValues = new ArrayList();
    nodeValues.add(node.getValue());
    nodeValues.addAll(traversePreRecursive(node.getLeft()));
    nodeValues.addAll(traversePreRecursive(node.getRight()));

    return nodeValues;
}

【讨论】:

  • 嘿抱歉,我想我对此并不十分清楚。我想知道是否有办法只使用普通数组而不是 ArrayList。
  • 另外,虽然这会起作用,但我觉得这比使用递归范围之外的数组效率要低得多......
  • 我怀疑使用数组会更有效。基本问题是知道要添加到数组中的元素数量。如果您知道这一点,那么您也可以预先确定数组列表的大小,并获得相同的好处。数组列表是一个相当简单的数组包装器,它为您管理数组的扩展,因此在不预先知道数组大小的情况下,您最终会自己编写这段代码,而且效率可能低于标准数组列表实现。
  • 对,我知道 ArrayList 是如何构建的。也许我只是天真,但不会调用 addAll 导致它必须在每次返回 traversePreRecursive 之后将列表中的每个元素重新写入列表?所以现在你有一个 O(n^2) 操作而不是 O(n) 操作?
  • 你有这样的想法是可以原谅的,但是 java 针对这种类型的操作进行了高度优化。在幕后addAll() 方法遵循System 对象上arrayCopy() 的本机实现,它以最快的方法实现(考虑到平台/jvm 实现的约束)——通常它使用 blitters和内存映射。这意味着该操作涉及在每个列表的单个操作中分配内存并将每个列表中的数据块复制到单个内存块中。
【解决方案2】:

有一个替代方案,但它涉及两次遍历树。如果我的第一个答案中的数组操作让您感到悲伤,您只会使用这种替代方法。这种方法首先为每个节点提供一个索引(index() 方法)——基本上在我们实际创建数组之前计算出一个节点应该占据数组的哪个元素。这也给了我一个节点数(size)。然后我分配一个足够大的数组 (list) 以容纳所有节点并将其传递给一个方法 (addToList),该方法将节点引用复制到数组中先前标识的元素中。

public static List<Node> getNodes(Node a) {
    int size = index(a, 0);
    List<Node> list = new ArrayList<Node>(size);
    addToList(a, list);
    return list;
}

private static int index(Node node, int index) {
    if (node == null) return index;

    node.setIndex(index);
    int iLeft = index(node.getLeft(), index++);
    int iRight = index(node.getRight(), iLeft++);

    return iRight + 1;
}

private static void addToList(Node node, List<Node> list) {
    if(node == null) return;
    list.add(node.getIndex(), node);
    addToList(node.getLeft(), list);
    addToList(node.getRight(), list);
}

【讨论】:

    【解决方案3】:

    在 c 中,您可以拥有静态函数变量,(即,在函数的一次迭代中将值添加到列表中意味着该值将在下一次迭代中出现在列表中——如果列表是静态的)但使用它们不是您建议的问题的最佳(最佳)解决方案。所以,我认为您正在搜索静态变量,但这不是使用它们的合适情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-12
      • 2014-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-26
      • 2017-05-11
      相关资源
      最近更新 更多