为什么我的引用TreeNode没有更改二叉树的节点?

时间:2015-04-11 09:14:49

标签: java reference binary-tree treenode

我正在研究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);
        }

    }
}

1 个答案:

答案 0 :(得分:0)

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

  • 参数的任何赋值都是而不是,只有在方法体内才会被调用者看到。无论它是原始的还是引用(对象)都是如此。
  • 如果变量是对可变对象的引用(即,您可以直接或使用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。下次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节点不为null,则它将等于给定元素,或者必须在其下的某处设置给定元素。所以左边节点是一个很好的“父”节点,我们可以用它来调用递归。

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

因为我们要直接分配到current.leftcurrent.right,这是我们给定的current字段,所以结果被来电者看到。