为什么我的Java二进制搜索树类在我告诉它时实际上没有删除节点?

为什么我的Java二进制搜索树类在我告诉它时实际上没有删除节点?,java,recursion,tree,binary-tree,Java,Recursion,Tree,Binary Tree,我正在用Java构建一个二叉搜索树,以便更好地理解它们是如何工作的,我正在开发一个函数来删除一个具有特定值的节点 我基本上是遍历树,直到找到具有正确值的节点,然后根据它有多少子节点来执行相应的操作 如果它没有子项,我将其设置为null。如果它有一个,我就把它自己和这个孩子一样。如果它有两个,我会遍历左边的树,沿着左边一直走到左边,然后删除它,并将我所在节点的值设置为已删除节点的值 class BTree { public int data; public BTree leftTr

我正在用Java构建一个二叉搜索树,以便更好地理解它们是如何工作的,我正在开发一个函数来删除一个具有特定值的节点

我基本上是遍历树,直到找到具有正确值的节点,然后根据它有多少子节点来执行相应的操作

如果它没有子项,我将其设置为null。如果它有一个,我就把它自己和这个孩子一样。如果它有两个,我会遍历左边的树,沿着左边一直走到左边,然后删除它,并将我所在节点的值设置为已删除节点的值

class BTree {
    public int data;
    public BTree leftTree;
    public BTree rightTree;

    public BTree(int data) {
        this.data = data;
    }

    public BTree(int data, BTree leftTree, BTree rightTree) {
        this.data = data;
        this.leftTree = leftTree;
        this.rightTree = rightTree;
    }

    public void insert(int data) {
        if (data < this.data) {
            if (this.leftTree == null) {
                BTree newTree = new BTree(data);
                this.leftTree = newTree;
            } else {
                insert(this.leftTree, data);
            }
        } else {
            if (this.rightTree == null) {
                BTree newTree = new BTree(data);
                this.rightTree = newTree;
            } else {
                insert(this.rightTree, data);
            }
        }
    }

    private void insert(BTree tree, int data) {
        if (tree.data == data) {
            return;
        }

        if (data < tree.data) {
            if (tree.leftTree == null) {
                BTree newTree = new BTree(data);
                tree.leftTree = newTree;
            } else {
                insert(tree.leftTree, data);
            }
        } else {
            if (tree.rightTree == null) {
                BTree newTree = new BTree(data);
                tree.rightTree = newTree;
            } else {
                insert(tree.rightTree, data);
            }
        }
    }

    public void inorderTraversal(BTree tree) {
        if (tree.leftTree != null) {
            inorderTraversal(tree.leftTree);
        }

        System.out.print(tree.data + ", ");

        if (tree.rightTree != null) {
            inorderTraversal(tree.rightTree);
        }
    }

    public void remove(int data, BTree tree) {
        if (tree == null) {
            return;
        }

        if (data == tree.data) {
            if (tree.leftTree != null && tree.rightTree != null) {
                int minimumValue = getMinimumValue(tree.leftTree);
                remove(minimumValue, tree);

                tree.data = minimumValue;
            } else if (tree.leftTree != null) {
                tree = tree.leftTree;
            } else if (tree.rightTree != null) {
                tree = tree.rightTree;
            } else {
                tree = null;
            }
        } else if (data < tree.data) {
            remove(data, tree.leftTree);
        } else {
            remove(data, tree.rightTree);
        }
    }

    public int getMinimumValue(BTree tree) {
        if (tree.leftTree == null) {
            return tree.data;
        } else {
            return getMinimumValue(tree.leftTree);
        }
    }

    public static void main(String[] args) {
        BTree myTree = new BTree(5);
        myTree.insert(6);
        myTree.insert(12);
        myTree.insert(4);
        myTree.insert(3);
        myTree.insert(6);
        myTree.insert(15);
        myTree.insert(1);
        myTree.insert(9);
        myTree.insert(-2);

        myTree.remove(3, myTree);

        myTree.inorderTraversal(myTree);
    }
}
类BTree{
公共int数据;
公共b树左树;
公共树;
公共BTree(int数据){
这个数据=数据;
}
公共BTree(int数据、BTree leftTree、BTree rightTree){
这个数据=数据;
this.leftTree=leftTree;
this.rightree=rightree;
}
公共空白插入(整型数据){
如果(数据<此数据){
if(this.leftTree==null){
BTree newTree=新的BTree(数据);
this.leftTree=newTree;
}否则{
插入(this.leftTree,data);
}
}否则{
if(this.rightree==null){
BTree newTree=新的BTree(数据);
this.rightree=newTree;
}否则{
插入(this.rightree,data);
}
}
}
私有void插入(BTree树,int数据){
if(tree.data==数据){
返回;
}
if(数据<树数据){
if(tree.leftTree==null){
BTree newTree=新的BTree(数据);
tree.leftTree=newTree;
}否则{
插入(tree.leftTree,数据);
}
}否则{
if(tree.rightree==null){
BTree newTree=新的BTree(数据);
tree.rightree=newTree;
}否则{
插入(tree.rightree,数据);
}
}
}
OrderTraversal中的公共无效(B树){
if(tree.leftTree!=null){
inorderTraversal(tree.leftTree);
}
系统输出打印(tree.data+“,”);
如果(tree.rightree!=null){
inorderTraversal(tree.rightree);
}
}
删除公共void(int数据,BTree树){
if(tree==null){
返回;
}
if(data==tree.data){
if(tree.leftTree!=null&&tree.rightree!=null){
int minimumValue=getMinimumValue(tree.leftTree);
移除(最小值,树);
tree.data=最小值;
}else if(tree.leftTree!=null){
tree=tree.leftTree;
}else if(tree.rightree!=null){
tree=tree.rightTree;
}否则{
tree=null;
}
}else if(数据<树数据){
删除(数据,tree.leftTree);
}否则{
删除(数据,tree.rightree);
}
}
公共int getMinimumValue(BTree树){
if(tree.leftTree==null){
返回树数据;
}否则{
返回getMinimumValue(tree.leftTree);
}
}
公共静态void main(字符串[]args){
BTree myTree=新的BTree(5);
myTree.insert(6);
myTree.insert(12);
myTree.insert(4);
myTree.insert(3);
myTree.insert(6);
myTree.insert(15);
myTree.insert(1);
myTree.insert(9);
myTree.insert(-2);
移除(3,myTree);
myTree.inorderTraversal(myTree);
}
}

尽管如此,3仍然显示在顺序遍历中。我做错了什么?

以这一行为例:

tree = tree.leftTree;
您正试图通过为
指定一个新值来重写树

但是
tree
是一个方法参数。通过在方法内部重新分配它,您并不是在方法调用点重新分配方法参数:方法参数是按值传递的,始终是。这意味着引用类型参数通过值传递,作为引用的值。方法中对该值(引用)的更改在原始调用站点上没有影响。对该引用类型的内容所做的更改将产生影响

值得引用Java教程>将信息传递给方法或构造函数>

引用数据类型参数(如对象)也通过值传递到方法。这意味着当方法返回时,传入的引用仍然引用与以前相同的对象。但是,可以在方法中更改对象字段的

看看这个简单的例子:

public static void main(String[] args) {
  A a1 = new A();
  System.out.println("before the method                 : " + a1);
  reassignFail(a1);
  System.out.println("after the method                  : " + a1);
}
static void reassignFail(A a1) {
  A a2 = new A();
  System.out.println("inside the method a2              : " + a2);
  a1 = a2;
  System.out.println("inside the method for parameter a1: " + a1);
}
static class A{
  int id;
  private static int iid;
  public A() { id = ++iid; }
  public String toString() { return "this is instance " + id; }
}
这张照片是:

before the method : this is instance 1 inside the method a2 : this is instance 2 inside the method for parameter a1: this is instance 2 after the method : this is instance 1 在方法之前:这是实例1 在方法a2内部:这是实例2 参数a1的方法内部:这是实例2 在方法之后:这是实例1
因此,您的重新分配对树结构没有影响。

您的第二次插入在我看来很奇怪,因为您只需要创建一个包含数据的新BTree,或者只需要使用您已经插入的相同插入来处理所有可能的情况。inOrderTraversal也是如此

对于remove,您需要返回一个BTree,以处理“this”引用就是您想要删除的引用的情况(您不能附加到“this”)

类BTree{
公共int数据;
公共b树左树;
公共树;
公共BTree(int数据){
这个数据=数据;
}
公共BTree(int数据、BTree leftTree、BTree rightTree){
这个数据=数据;
this.leftTree=leftTree;
this.rightree=rightree;
}
公共空白插入(整型数据){
if(this.data==数据){
返回;
class BTree {

    public int data;
    public BTree leftTree;
    public BTree rightTree;

    public BTree(int data) {
        this.data = data;
    }

    public BTree(int data, BTree leftTree, BTree rightTree) {
        this.data = data;
        this.leftTree = leftTree;
        this.rightTree = rightTree;
    }

    public void insert(int data) {
        if (this.data == data) {
            return;
        }

        if (data < this.data) {
            if (leftTree == null) {
                leftTree = new BTree(data);
            } else {
                leftTree.insert(data);
            }
        } else {
            if (this.rightTree == null) {
                rightTree = new BTree(data);
            } else {
                rightTree.insert(data);
            }
        }
    }

    public void inOrderTraversal() {
        if (leftTree != null) {
            leftTree.inOrderTraversal();
        }

        System.out.print(data + ", ");

        if (rightTree != null) {
            rightTree.inOrderTraversal();
        }
    }

    //the void equivalents are in comments
    public BTree remove(int data) {
        if (data == this.data) {
            if (leftTree != null && rightTree != null) {
                //this is the only legal case for the void remove.
                int minValue = getMinimumValue();
                this.data = minValue;
                //leftTree.remove(minValue); //and no return is needed
                leftTree = leftTree.remove(minValue);
                return this;
            } else if (leftTree != null) {
                //this = leftTree; //illegal
                return leftTree;
            } else if (rightTree != null) {
                //this = rightTree; //illegal
                return rightTree;
            } else {
                //this = null; //illegal
                return null;
            }
        } else if (data < this.data) {
            leftTree = leftTree.remove(data);
            return this;
        } else {
            rightTree = rightTree.remove(data);
            return this;
        }
    }

    public int getMinimumValue() {
        if (leftTree == null) {
            return data;
        } else {
            return leftTree.getMinimumValue();
        }
    }

    public static void main(String[] args) {
        BTree myTree = new BTree(5);
        myTree.insert(6);
        myTree.insert(12);
        myTree.insert(4);
        myTree.insert(3);
        myTree.insert(6);
        myTree.insert(15);
        myTree.insert(1);
        myTree.insert(9);
        myTree.insert(-2);

        myTree = myTree.remove(3);

        myTree.inOrderTraversal();
    }
}