有代码:
public class BST {
public Node root;
private class Node {
int key;
String value;
int N;
Node left, right;
public Node(int k, String v, int n) {
key = k;
value = v;
N = n;
}
}
public String get(int key) {
return get(root, key);
}
private String get(Node n, int k) {
if(n == null) {
return null;
}
if(k == n.key) {
return n.value;
} else {
if(k < n.key) {
return get(n.left, k);
} else {
return get(n.right, k);
}
}
}
// This snippet puzzles me
public void put(int key, String value) {
root = put(root, key, value);
}
private Node put(Node n, int k, String v) {
if(n == null) {
return new Node(k, v, 1);
}
if(n.key == k) {
n.value = v;
} else {
if(k < n.key) {
n.left = put(n.left, k, v);
} else {
n.right = put(n.right, k, v);
}
}
n.N = size(n.left) + size(n.right);
return n;
}
// snippet ends
public static void main(String[] args) {
BST r = new BST();
r.put(2, "root");
r.put(1, "left");
r.put(3, "right");
System.out.println(r.get(2));
System.out.println(r.get(1));
System.out.println(r.get(3));
}
}
输出:
root
left
right
一切正常:)
但是,当我像这样更改put
方法时:
public void put(int key, String value) {
put(root, key, value);
}
private void put(Node n, int k, String v) {
if(n == null) {
n = new Node(k, v, 1);
}
if(n.key == k) {
n.value = v;
} else {
if(k < n.key) {
put(n.left, k, v);
} else {
put(n.right, k, v);
}
}
n.N = size(n.left) + size(n.right);
}
我得到了输出
null
null
null
显然,新的put
方法失败了。但为什么?在我看来,这两种不同的实现方式差别不大。
答案 0 :(得分:1)
更改作业时
n.left = put(n.left, k, v);
到
put(n.left, k, v);
(或与n.right相同),并且您还没有节点,您将新节点分配给n变量,但您没有更新链接从递归调用返回的父项到子项。因此,新节点将保持孤立状态,因为您在最后一次递归调用中更改了n的引用,而不是n.left(或右)父级引用。此外,我猜测当参考n的值将在最后一次递归调用结束时被释放,因为没有其他引用指向新创建的节点,这最终将被垃圾收集器消除。
答案 1 :(得分:1)
在Java中,当您阅读Node n
时,n
是引用的本地副本。分配此本地副本时,它不会更改调用方中的副本。即
private void put(Node n, int k, String v) {
if(n == null) {
n = new Node(k, v, 1); // this doesn't change the caller.
}
如果您没有返回要分配给root
,n.left
或n.right
的节点,那么您正在创建一个节点,但是您没有将其添加到树。
如果您想进一步调查此问题,我建议您逐步调试调试器中的代码,您将能够看到每行代码的作用。