【问题标题】:Why isn't my reference TreeNode changing the nodes of my binary tree?为什么我的参考 TreeNode 没有改变我的二叉树的节点?
【发布时间】:2015-04-11 09:14:49
【问题描述】:

我正在开发一个 BinarySearch 程序,并且正在研究将值插入到树中的方法。

但是,当我运行代码时,根变量的节点并没有随着引用变量 current 而改变。

这是为什么?

我的代码:

public boolean insert(E element) {
    return insert(element, root);

}

private boolean insert(E element, OrderedSet<E>.TreeNode current) {
    if (current == null) {
        current = new TreeNode(element);
        return true;
    }

    if (current.data.compareTo(element) == 0) {
        return false;
    } else {

        if (current.data.compareTo(element) > 0) {
            return insert(element, current);
        } else {
            current = current.right;
            return insert(element, current);
        }

    }
}

【问题讨论】:

  • current 是按值传递,而不是按引用传递。你不能给它赋值并期望在调用者中取回它。
  • 知道如何解决它吗?

标签: java reference binary-tree treenode


【解决方案1】:

Java 参数总是按值传递。当参数是 reference 变量时,这有点令人困惑。需要注意的是:

  • 对参数的任何赋值不会被调用者看到,只能在方法体内看到。无论是原始的还是引用(对对象)都是如此。
  • 如果变量是对可变对象的引用(即,您可以直接或使用 setter 访问和更改其字段的对象),则将进行 对字段的赋值来电者可以看到。

那么我们可以对上述程序做些什么呢?假设您可以访问TreeNode 对象的leftright 字段,您应该更改方法以便current 参数始终代表任何添加节点的 节点。这样一来,它就永远不会是null,它永远是一个真实的对象。在一个真实的对象中,我们可以改变字段!

所以我们从top方法开始:

public boolean insert(E element) {
    if ( root == null ) {
        root = new TreeNode( element );
        return true;
    } else {
        return insert(element, root);
    }
}

如果我们的树中还没有任何东西——根为空——那么我们根本就不能调用我们的递归方法。就目前而言,没有“父”节点可以通过。但在这种情况下,正确的做法是将root 设置为给定元素。因此,我们使用给定的元素创建一个新节点,并将其分配给根。下一次,root 将不再是 null

如果它不为 null,我们可以将其作为插入的“父级”传递。要么它的内容等于新元素(在这种情况下,递归方法将返回 false),要么该项目必须插入到它 的某处。所以它是一个很好的“父母”。

现在是递归方法本身:

private boolean insert(E element, OrderedSet<E>.TreeNode current) {

    if (current.data.compareTo(element) == 0) {

        // The element is already in the tree, so we do not insert
        // anything, and we return false.

        return false;
    } else {

        if (current.data.compareTo(element) > 0) {

            // Smaller elements need to be inserted at the left

            if ( current.left == null ) {
                current.left = new TreeNode( element );
                return true;
            } else {
                return insert(element, current.left );
            }

        } else {

            // Bigger elements need to be inserted at the right

            if ( current.right == null ) {
                current.right = new TreeNode( element );
                return true;
            } else {
                return insert(element, current.right );
            }

        }

    }
}

现在,每种情况(更大和更小)的代码都变得稍微复杂了一点:

            if ( current.left == null ) {
                current.left = new TreeNode( element );
                return true;
            } else {
                return insert(element, current.left );
            }

我们不再允许将null 传递给下一个递归步骤,因为null 不是正确的“父级”,我们将无法分配给它的字段。所以如果左分支为空,我们就不能递归。但在这种情况下,适当的操作是将左节点实际设置为我们的新元素,因为它 比我们当前的节点小。所以我们新建一个节点,设置current.left来引用它,现在我们在树上添加了一些东西,我们可以返回true

但是如果left 节点不为空,那么它要么等于给定元素,要么必须将给定元素设置在它下面的某个位置。所以左节点是一个很好的“父”节点,我们可以用它来调用递归。

同样的逻辑也适用于向右添加元素。

因为我们直接分配给current.leftcurrent.right,它们是我们给定current字段,所以调用者会看到结果

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-19
    • 2020-06-03
    • 1970-01-01
    • 2017-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-02
    相关资源
    最近更新 更多