java - 为什么我的 Java Binary Search Tree 类在我告诉它时实际上没有删除节点?

标签 java recursion tree binary-tree

我正在用 Java 构建二叉搜索树以更好地理解它们的工作原理,并且我正在研究删除具有特定值的节点的函数。

我基本上遍历树,直到找到具有正确值的节点,然后根据它有多少个 child 采取相应的行动。

如果它没有 child ,我将其设置为空。如果它有一个,我将自己设置为等于 child 。如果它有两个,我遍历左边的树,跟随左边直到到达左边,然后删除它并将我所在的节点的值设置为已删除节点的值。

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

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

最佳答案

以这一行为例:

tree = tree.leftTree;

您正在尝试通过为 tree 分配新值来重写树。

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

值得引用 The Java Tutorials > Passing Information to a Method or a Constructor > Passing Reference Data Type Arguments

Reference data type parameters, such as objects, are also passed into methods by value. This means that when the method returns, the passed-in reference still references the same object as before. However, the values of the object's fields can be changed in the method

看这个简单的例子:

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

所以你的重新分配对树结构没有影响。

关于java - 为什么我的 Java Binary Search Tree 类在我告诉它时实际上没有删除节点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28597497/

相关文章:

algorithm - 计算二叉树的大 O : there is a custom tag for each node

algorithm - 行为树实现

java - 需要日历算法方面的帮助

Java 正则表达式 : Word Boundary Matcher in a String Literal

java - 我正在研究 Euler 12,我的代码似乎可以正常工作,但是太慢了,非常非常慢。我该如何修改它才能运行得更快?

javascript - 使用递归的加权作业调度

java - 在数组递归中计算从一个点到另一个点的路径,而不重复单元格

java - 有界通配符相关的编译器错误

python - Python 递归中的通用树

C++目录树数据转化为 vector