将节点添加到树 - 为啥根没有被初始化?
Posted
技术标签:
【中文标题】将节点添加到树 - 为啥根没有被初始化?【英文标题】:Adding node to tree - Why is the root not getting initialized?将节点添加到树 - 为什么根没有被初始化? 【发布时间】:2020-09-30 09:25:14 【问题描述】:我编写了两个用于向树中添加新节点的函数:一个public 和一个private。私有的是递归的。公共的称为递归的。第一个问题:这是可以接受的做法吗?
public void addNode(int val)
addNode(val, root, null, 0);
System.out.println("Root is null: " + (root == null));
private void addNode(int val, Node node, Node parent,int height)
if(node == null)
node = new Node(val, height, 0);
System.out.println("is new node equal to root?"+(node == root));
System.out.println("Added node on height: " + node.getHeight());
return;
height++;
addNode(val, node.left, node, height);
addNode(val, node.right, node, height);
现在问题来了:根变量没有被初始化。它在树类中声明。 public Node root;
这让我很困惑,因为我知道 Java 是按引用传递,而不是按值传递。为什么调用这些函数后root为空?
控制台输出:
is new node equal to root?false
Added node on height: 0
Root is null: true
【问题讨论】:
new Node(val, height, 0);
中的第三个参数是什么?
即大小(子树中节点的数量)@trincot
【参考方案1】:
如果在 Java 代码中函数为函数参数分配一个新值,这绝不会影响调用者可能已作为参数传递的变量。您可能对当参数变量变异时会发生什么感到困惑:例如,如果它是一个对象并且您为它的一个属性分配了不同的值,那么调用者可以看到此更改对象,因为它确实是同一个对象。但是对参数的简单赋值总是只会对该局部变量产生影响。
要使其工作,请将您的函数设计为返回您提供给它的节点(无论它是否有新值)。
还有一个问题:您当前在左右子树中都添加了一个新节点(如果它们存在的话),并且这会递归地重复。我假设您尝试在二叉树中插入值搜索,因此您应该选择在哪个子树中添加节点。
最后,不需要传递parentNode
或height
作为参数,因为您似乎将高度存储在每个节点中,因此您知道新节点的高度必须比存储的高度大一它的父节点(或者,如果不存在,则为 0)。
public void addNode(int val)
root = addNode(val, root);
private void addNode(int val, Node node)
if (node == null)
return new Node(val, 0, 0); // NB: height will be updated when backtracking
if (val < node.val)
node.left = addNode(val, node.left);
node.left.height = node.height + 1;
else
node.right = addNode(val, node.right);
node.right.height = node.height + 1;
return node;
最后,“高度”这个名字在这里有点误导,因为这个术语应该表示节点是根的(子)树的高度。但是这段代码中的height
代表了树中节点的深度。见What is the difference between tree depth and height?。
【讨论】:
一个非常有帮助和清晰的答案。谢谢! @trincot【参考方案2】:当然,从公共方法调用私有方法(甚至是递归的)并没有错。
Root 为 null 仅仅是因为您正在为 node
参数分配新值,您并没有更改对象,而是创建了新对象。
关注
private void addNode(int val, Node node, Node parent,int height)
...
node = new Node(val, height, 0);
不会更改调用者中的参数node
。所以调用后
addNode(val, root, null, 0);
root
保持不变(null
值)
还要记住对象在 Java 中是按值传递的。
实际上(在 Java 中)在函数中,您只收到 node
的内存地址(值)(例如 x64 架构中的 000000D5098FFA70
)。因此,如果您修改例如node.left
您实际上正在更改地址 000000D5098FFA70 + 4
的内存。但是,如果你改变
该地址 - 值 - 您无法访问该对象。从那一刻起,您只使用局部变量。这就是为什么它被称为按值传递。
【讨论】:
以上是关于将节点添加到树 - 为啥根没有被初始化?的主要内容,如果未能解决你的问题,请参考以下文章
将第一个节点添加到hashmap中的链表时,为啥必须将新节点直接分配给索引指针?