Java 参数总是按值传递。当参数是 reference 变量时,这有点令人困惑。需要注意的是:
- 对参数的任何赋值不会被调用者看到,只能在方法体内看到。无论是原始的还是引用(对对象)都是如此。
- 如果变量是对可变对象的引用(即,您可以直接或使用 setter 访问和更改其字段的对象),则将进行 对字段的赋值来电者可以看到。
那么我们可以对上述程序做些什么呢?假设您可以访问TreeNode 对象的left 和right 字段,您应该更改方法以便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.left 和current.right,它们是我们给定current 的字段,所以调用者会看到结果。