【问题标题】:Failing to set a node to null未能将节点设置为空
【发布时间】:2022-11-11 05:24:56
【问题描述】:

我正在尝试构建二叉搜索树,但在创建自己的删除节点的方法时遇到问题。

我知道当一个节点有两个孩子(一个孩子或没有孩子)时如何删除它,我在我的代码中已经考虑到了这一点。但是当我真的想删除它并将其设置为 null 时,什么也没有发生。节点仍然存在,并且当节点有两个孩子时,最小的数字不会替换它。 (一种处理删除具有两个孩子的节点的技术)。问题出在哪里?

下面是代码:

public static void main(String[] args) {
    BST root=new BST(10);
    root.insert(5);
    root.insert(15);
    root.insert(2);
    root.insert(5);
    BST node=root.insert(13);
    root.insert(22);
    root.insert(1);
    root.insert(14);
    BST smallestNode=root.insert(12);
    System.out.println(node.left.value);
    System.out.println(root.contains(4));
    System.out.println(root.remove(12));
    System.out.println(root.contains(12));
}

public static class BST {
    public int value;
    public BST left;
    public BST right;

    public BST(int root) {
        this.value = root;
    }

    public BST insert(int value) {
        BST currentNode=this;
        while(true){
            if(value>= currentNode.value){
                if(currentNode.right ==null){
                    currentNode.right=new BST(value);
                    currentNode=currentNode.right;
                    break;
                }
                currentNode= currentNode.right;
            }else{
                if(currentNode.left==null){
                    currentNode.left=new BST(value);
                    currentNode=currentNode.left;
                    break;
                }
                currentNode= currentNode.left;
            }
        }
        return currentNode;
    }
    public boolean contains(int value) {
        BST currentNode=this;
        while(true){
            if(value>= currentNode.value){
                if(currentNode.right ==null){
                    return false;
                }
                currentNode= currentNode.right;
                if(currentNode.value==value){
                    return true;
                }
            }else{
                if(currentNode.left==null){
                    return false;
                }
                currentNode= currentNode.left;
                if(currentNode.value==value){
                    return true;
                }
            }
        }
    }
    public BST remove(int value) {
        BST currentNode=this;
        if(currentNode.right==null &&currentNode.left==null){
            return this;
        }
        while(true){
            if(value>= currentNode.value){
                if(currentNode.right==null){
                    return this;
                }
                currentNode= currentNode.right;
                if(currentNode.value==value){
                    if(currentNode.left!=null&&currentNode.right==null){
                        currentNode=currentNode.left;
                        return currentNode;
                    }else if(currentNode.right!=null&&currentNode.left==null){
                        currentNode=currentNode.right;
                        return currentNode;
                    }else if(currentNode.right==null&&currentNode.left==null){
                        currentNode=null;
                        return currentNode;
                    }else{
                        currentNode.value=smallestValueSearchService(this);
                        currentNode.right=this.right;
                        currentNode.left=this.left;
                        return currentNode;
                    }
                }
            }else{
                if(currentNode.left==null){
                    return this;
                }
                currentNode= currentNode.left;
                if(currentNode.value==value){
                    if(currentNode.left!=null&&currentNode.right==null){
                        currentNode=currentNode.left;
                        return currentNode;
                    }else if(currentNode.right!=null&&currentNode.left==null){
                        currentNode=currentNode.right;
                        return currentNode;
                    }else if(currentNode.right==null&&currentNode.left==null){
                        currentNode=null;
                        return currentNode;
                    }else{
                        currentNode.value=smallestValueSearchService(this);
                        currentNode.right=this.right;
                        currentNode.left=this.left;
                        return currentNode;
                    }
                }
            }
        }
    }
}
//?: conditional
public static int smallestValueSearchService(BST binaryTree){
    if(binaryTree.left==null){
        int temp=binaryTree.value;
        binaryTree=null;
        return temp;
    }else{
        return smallestValueSearchService(binaryTree.left);
    }
}
  1. 这是我应该实现的目标以及我的代码产生的结果的直观说明:

    1. 这是二叉树:

【问题讨论】:

  • 请提供一个可运行的示例来说明您的问题。阅读How to Ask

标签: java binary-tree


【解决方案1】:

主要问题是分配给多变的永远不会改变树的任何东西。变量currentNode 引用一个节点,当您将currentNode 设置为其他节点引用或null 时,您只需修改该变量的内容,而不是树中的任何内容。

这种误解可以在removesmallestValueSearchService 中看到。尽管后一个函数名称表明它只是搜索一个值,你似乎想要消除一个值。但是那里也没有任何东西被删除。

关于您的 remove 方法,还有其他一些事项需要注意,包括:

  • 第一个if 将只返回当前节点而不检查其值(它可能是要删除的值!)。
  • 有相当多的代码重复。应该避免这种情况。
  • while 循环毫无意义,因为在所有情况下,return 都将在其第一次(也是唯一一次)迭代中执行。
  • 因为循环不循环,也没有递归,currentNode 永远不会引用树中比其前两级更深的节点。
  • remove 返回一个节点引用,但实际上没有 remove 的调用者做某事与该返回值。这是一个关键点,因为调用者应该分配它到一个节点。例如,如果树只有一个节点,并且它有要删除的值,那么您应该在某处将root 设置为null
  • smallestValueSearchServicethis 作为参数调用,但这是错误的。它应该在具有要删除的值的节点的右子树中查找最小值。

奇怪的是,您将smallestValueSearchService 定义为静态方法而不是实例方法。我还建议这个函数将只返回最小值并且不会尝试删除它。然后,您可以在找到它后使用remove 方法实际删除它。

这是remove 函数的更正。我将smallestValueSearchService静态方法重命名为getSmallestValue,现在它是一个实例方法:

    public BST remove(int valueToRemove) {
        if (valueToRemove > value) {
            if (right != null) {
                right = right.remove(valueToRemove);
            }
        } else if (valueToRemove < value) {
            if (left != null) {
                left = left.remove(valueToRemove);
            }
        } else {
            if (right == null) {
                return left;
            } else if (left == null) {
                return right;
            } else {
                value = right.getSmallestValue();
                right = right.remove(value);
            }
        }
        return this;
    }
    
    public int getSmallestValue(){
        if (left == null) {
            return value; 
        } else {
            return left.getSmallestValue();
        }
    }

主程序不应打印来自remove 调用的结果,而是将其分配给root 变量:

        root = root.remove(12);

【讨论】:

  • 非常感谢您的详细解释和指导!这对我很重要。
  • 请问为什么BST类必须是静态的?它不依赖于我们创建的任何变量吗?
  • 另外,我不明白你如何摆脱包含 valueToRemove 的节点
  • 如果 BST 类在其自己的模块中定义,则它不必是静态的,但我想你把它放在你定义了静态 main 函数的类中,这解释了为什么它必须是静态的(因为有没有你的主类的实例)。
  • 通过不将节点返回给调用者来删除该节点。然后调用者将缩减的子树分配给其leftright 成员。
猜你喜欢
  • 2012-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-03
  • 1970-01-01
  • 2022-01-23
  • 2023-03-10
相关资源
最近更新 更多