Java递归 - 传递引用的替代方法:

时间:2016-10-28 05:53:03

标签: java recursion pass-by-value

我正在从C迁移到Java并且我在递归方面遇到了困难,特别是因为在Java中你无法通过引用传递参数。

我正在寻找的不是强制Java通过引用传递参数的解决方案/技巧,而是推荐用Java解决此类问题的方法。

让我们在二叉树中插入递归节点:

void nodeInsert(Node n, int a) {
    if (n == null)
        n = new Node(a);
...
}

在C中,在执行结束时,树中的节点n将指向新创建的节点。但是,在Java中,n仍然是null(因为n是按值传递的)。

针对此类问题建议的Java方法是什么? 我已经尝试了一些方法:

  • 使用静态对象跟踪父级(使用泛型时问题复杂)。
  • 将父节点作为函数的一部分传递。它有效,但有点使代码复杂化,看起来不是一个好的解决方案。
  • 创建指向父节点的其他成员,但这不是一个好的解决方案,因为它会增加O(n)所需的空间;

欢迎任何建议。

5 个答案:

答案 0 :(得分:3)

在Java中,而不是使用引用变量,我们使用 return 值并将其分配给必须更改的变量。

    Node nodeInsert(Node n, int a) {
        if (n == null){
            n = new Node(a);
            return n;
        }
        else
        {
            ....
            return nodeInsert(n,a); //this is how a recursion is done.
            ....
        }

    }

如果您在递归时需要更多http://www.toves.org/books/java/ch18-recurex/,则会教你正确。

答案 1 :(得分:2)

实现的常用方法是维护节点本身内的节点关系。在各种JDK数据结构的实现中可以找到相当多的示例。因此,Node是值的容器,并包含对其他节点的引用,具体取决于数据结构。

如果节点之间需要子 - >父关系,则Node类看起来像

class Node<T> {
    T value;
    Node parent;
}

如果是insert,则创建一个新节点,将父引用设置为原始节点,然后返回新节点(这是可选的,但并不罕见,因此调用具有新生儿)

Node<T> insert(Node<T> parent, T value) {
  Node<T> child = new Node<>();
  child.value = value;
  child.parent = parent;
  return child;
}

是的,这会增加每个节点4个字节的小开销(或8个字节,在没有压缩指针的64位JVM上)

答案 2 :(得分:1)

我提出以下解决方案:

  • 在类Node中实现一个添加子节点的方法。这利用了OO可能性将数据和功能封装在一起。

  • 更改nodeInsert以返回新节点并将其添加到调用方中的父节点(也在注释中提及)。 nodeInsert的职责是创建节点。这是一个明确的责任,方法签名显示了该方法的结果。如果创建时间不超过new Node(),则可能无法为其创建单独的方法。

答案 3 :(得分:0)

您可以传递一个持有者对象,该对象又会引用您的新Node对象

void nodeInsert(AtomicReference<Node> r, int a) {
    if (r.get() == null)
        r.set(new Node(a));
...
}

或者你可以为一个元素传递一个带空格的数组。

答案 4 :(得分:0)

在发布这个问题几个月之后,我意识到另一个解决方案实际上已经在java设计模式中考虑过了,但这里没有提到:Null Object Pattern。 缺点是每个空占用内存(在某些情况下,像大红黑树一样,这可能会变得很重要)。