我上次询问similar question关于下面第二个算法的问题并被引用到Is Java “pass-by-reference” or “pass-by-value”?线程。
当你将一个变量传递给一个方法时,我会得到它,Java会创建一个它的阴影副本,这样你就无法修改原始变量,但这正是让我感到困惑的原因。
下面是我最初在根节点中传递的两个有点类似的算法 - 第一个可以工作,但第二个没有。
第一
public void insert(int element) {
Node temp = new Node(element);
if(root == null) {
root = temp;
root.parent = null;
size++;
} else {
insert(root, temp);
size++;
}
}
private void insert(Node current, Node temp) {
if(temp.element < current.element) {
if(current.leftChild == null) {
current.leftChild = temp;
} else {
insert(current.leftChild, temp);
}
}
else if(temp.element >= current.element) {
if(current.rightChild == null) {
current.rightChild = temp;
} else {
insert(current.rightChild, temp);
}
}
}
输出继电器:
秒(不起作用)
public void insert(int data) {
Node temp = new Node(data);
if(root == null) {
root = temp;
size++;
} else {
insert(root, temp);
size++;
}
}
private void insert(Node current, Node temp) {
if(current == null)
current = temp;
else if(temp.element < current.element)
insert(current.leftChild, temp);
else if(temp.element >= current.element)
insert(current.rightChild, temp);
}
输出:
我自己写了第一个,并从Wikipedia获得了第二个。为什么第一个工作而不是第二个?
答案 0 :(得分:1)
它不起作用,因为您没有在树中连接元素'temp'。 假设您已到达必须在树中添加临时值的位置。假设 在某个阶段你有最新的和
current.leftchild = null ,你必须在这里添加temp。在第二种方法中做的是 你必须 current.leftchild 并为其分配 temp ,但你实际上没有指出 左指向temp.Thus temp 的指针将无法访问,也不会形成树。 那就是你必须保留返回类型Node来解决问题。
答案 1 :(得分:1)
让我们来看看哪些参考文献。 (Java引用,不要与C ++混淆 - 引用)
假设我们有一些带地址的内存,在这种情况下,数据是一些字符串对象
[ address ][ data ]
[ 0 ][ abc ]
[ 1 ][ de ]
[ 2 ][ y ]
[ 3 ][ foo ]
[ 4 ][ baar ]
如果我们有一个引用,那么这个引用只是一个地址,而不是数据本身!
int i = 15; // this is a primitive type, the variable i holds the data directly
// 15 in this case
Number x = new StringObject(foo); // this is a reference, the reference only
// contains the address.
// so x is actually '3'
现在,如果我们调用方法会发生什么?传递给方法的每个值都将被复制。
void call(int x) {
x = 4;
}
int i = 15;
call(i);
System.out.println(i);
此输出将为15.因为i
的值被复制到调用方法。并且该方法仅更改副本,但不更改原始i。
参考资料也是如此:
void call(StringObject x) {
x = new StringObject("baz"); // this creates a new address in x!
}
StringObject i = new StringObject("foo"); // remember, i is only an address!
// the address is '3'
// the actual value can be looked up
// in our memory table above
// '3' -> 'foo'
call(i);
System.out.println(i);
此处的输出为foo
。与原语一样,i
将被复制。但不要担心,只会复制地址。结果是,调用方法适用于i
的副本3
。但原始i
的值不会更改。
那么,你问题的联系是什么?请参阅此方法:
private void insert(Node current, Node temp) {
if(current == null)
current = temp;
else if(temp.element < current.element)
insert(current.leftChild, temp);
else if(temp.element >= current.element)
insert(current.rightChild, temp);
}
显然,您可以看到,您的代码在current
引用的副本上运行!您正在更改将在方法之后丢弃的副本。基本上第二个代码解决问题的方法是使用第一个代码片段。你可以使用一些包装器对象,比如C ++ - 引用,但是这很复杂并且容易出错。