当前位置: 首页 > 知识库问答 >
问题:

向树添加节点-为什么根没有被初始化?

西门骁
2023-03-14

我写了两个函数,用于在树中添加一个新节点:一个公共的和一个私有的。私有的是递归的。公共的调用递归的。第一个问题:这是可以接受的做法吗?

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);

}

现在问题来了:根变量没有初始化。它在树类中声明<代码>公共节点根

这让我非常困惑,因为我知道Java是按引用传递的,而不是按值传递的。为什么在调用这些函数后root为null?

控制台输出:

is new node equal to root?false
Added node on height: 0
Root is null: true

共有2个答案

陆飞捷
2023-03-14

当然,从公共方法调用私有方法(甚至递归)并没有什么错。Root为null仅仅是因为您正在为节点参数分配新值,您并没有更改对象,而是在创建新对象。

以下内容

private void addNode(int val, Node node, Node parent,int height) {
   ...
   node = new Node(val, height, 0);

不会更改调用方中的参数节点

addNode(val, root, null, 0);

root保持不变(使用null值)

还要记住,在Java中,对象是按值传递的。

实际上(Java)在函数中,您只收到节点的内存地址(值)(例如x64 arch中的000000D5098FFA70)。因此,如果您修改例如node.left,您实际上是在地址0000D5098FFA70 4处更改内存。然而,如果您更改了地址值,您将失去对该对象的访问权限。从那时起,您只能使用局部变量。这就是为什么它被称为按值传递。

上官迪
2023-03-14

如果在Java代码中,一个函数为一个函数参数分配了一个新的值,这永远不会影响调用者作为参数传递的变量。您可能对参数变量发生变化时会发生什么感到困惑:例如,如果它是一个对象,并且您为它的一个属性指定了不同的值,那么调用方的对象就可以看到这种变化,因为它实际上是同一个对象。但对参数的简单赋值总是只对局部变量有影响。

为了让它工作,设计你的函数来返回你提供给它的节点(不管它是否有新的值)。

还有另一个问题:您当前正在左子树和右子树(如果存在)中添加一个新节点,这会递归重复。我假设您试图在二叉搜索树中插入值,因此您应该选择在哪个子树中添加节点。

最后,不需要将父母节点高度作为参数传递,因为您似乎将高度存储在每个节点中,因此您知道新节点的高度必须比其父节点中存储的高度多一个(或者,如果不存在,则为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”有点误导,因为这个术语应该表示节点为根的(子)树的高度。但此代码中的height表示节点在树中的深度。看看树的深度和高度有什么区别?。

 类似资料:
  • 我正在将XML返回到一个jsp页面。 最终的XML结构如下所示: 的根节点作为向量返回,我使用xtream将其别名为“tasks”,如上图所示。 如何使用XStream实现这一点?我需要使用XSLT文件来转换XML输出吗?完成这一点的最佳方法是什么?

  • 我有一个XML: 我想向根元素:/doc添加一个属性(名称空间),以便输出如下所示: 我尝试了三种xslt(跳过了默认的“复制所有”部分以减少问题的长度)。 xslt1:见下文,问题在于将空名称空间xmlns=”“添加到/doc的所有子节点(即:/doc/tag1和/doc/tag2) Xslt2:见下文,问题是“ns”被添加到根节点:和 xslt3:请参见下文,问题是报告了错误:未定义名称空间前

  • 为什么x没有在下面初始化? 平均而言,对于一半的迭代,for循环中的将是,从而初始化。对于另一半,找到的 循环替换为 同样糟糕。只有

  • 问题内容: 我当时正在编写一个简短的脚本来更改元素的内部文本,但是发现它没有方法。我知道那不是继承自,但似乎不是一种有用的方法吗?是否有一个具体的实施问题,我不知道阻止添加的到? 注意:我知道Dojo和jQuery 的节点列表都有某种形式。由于限制,我无法使用任何一个。 问题答案: 现在,NodeList在所有主要浏览器中都具有forEach() 原始答案 这些答案都不能解释 为什么 NodeLi

  • 我正在做一个项目,以创建一个超过2个子节点的树。我明白在创建二叉树时,我们可以只创建一个左节点和一个右节点来充当子节点,但当我在网上寻找创建树的帮助时,我找到的每一个解决方案都谈到了创建二叉树。我明白创建树的部分意味着您需要创建子节点数组或arraylist,但我不明白如何将数据放入数组,或者如何将子节点数组“连接”到父节点? 这是我目前掌握的代码。我知道这不是很多,但我正在努力刚刚开始这个项目。

  • 如果我有一个struct Foo和一个struct Bar: 如果我初始化一个条并打印正确得到的值: 但是现在如果我声明这样的构造函数: 我失去了Bar::foo的默认构造,程序输出了32764 0 5! 为什么我不得不像这样无声地初始化每个成员变量: 只要我声明一个构造函数?在这种情况下,为什么默认构造不起作用?