Algorithm 为什么在代码中需要这一行才能从BST中删除?

Algorithm 为什么在代码中需要这一行才能从BST中删除?,algorithm,data-structures,binary-search-tree,Algorithm,Data Structures,Binary Search Tree,我正在努力学习更多关于二叉树的知识,我遇到了一个如何找到后续节点的方法(当试图删除节点时),我很难理解其中的一部分。 这是密码 private Node getSuccessor(Node delNode){ Node successorParent = delNode; Node successor = delNode; Node current = delNode.rightChild; while(current != null){

我正在努力学习更多关于二叉树的知识,我遇到了一个如何找到后续节点的方法(当试图删除节点时),我很难理解其中的一部分。 这是密码

    private Node getSuccessor(Node delNode){
    Node successorParent = delNode;
    Node successor = delNode;
    Node current = delNode.rightChild;

    while(current != null){
        successorParent = successor;
        successor = current;
        current = current.leftChild;
    } // end of if

    if(successor != delNode.rightChild){
        successorParent.leftChild = successor.rightChild;
        successor.rightChild = delNode.rightChild;
    }
    return successor;


}
我完全理解while循环和其中发生的事情。我不明白的是if声明,特别是

successor.rightChild = delNode.rightChild;
为什么要将delNode的正确子节点分配给后续节点的正确子节点?为什么需要if语句?

GetSuccession()的作用是查找delNode的后续节点,即最小值大于delNode的节点,即delNode下右子树中最左边的节点。然后将其从右子树中移除,并将右子树附加到后续子树下的右侧

使用条件的原因是,如果后继节点是delNode的正确子节点,则它已经位于正确子树的顶部,并且不需要将其从子树中取出并移动到子树的顶部

在下一步中,将删除delNode,后续节点将附加到delNode的父节点,delNode下的左侧子树将附加到后续节点下的左侧子树。所有这些的效果是用其继任者取代delNote

(此方法不是从二叉树中删除节点的最直接的方法。您可以简单地将右子树附加到delNode的父树,将左子树附加到后续树下的左侧。但此更复杂的方法的优点是不增加树的高度,因为每个节点都保持在相同的深度,或者移动到c彻底失败。)

下面是一个我们要删除节点3的示例:我们发现它的后继节点是4,我们从右子树中删除4并将其放置在子树的顶部,然后我们用后继节点4替换节点3并将左子树附加到它:

      9                                                9
     / \                                              / \
    3  ...                        4                  4  ...
   / \                             \                / \
  2   6              6              6              2   6
 /   / \            / \            / \            /   / \
1   4   7          4   7          5   7          1   5   7
     \   \          \   \              \                  \
      5   8          5   8              8                  8
(您会注意到,删除节点后,每个节点的深度都与之前相同,或者已移近根,因此树的高度没有增加。)

现在考虑一个例子,我们将再次删除节点3,但是我们发现它的继承者节点4已经在右子树的顶部,这意味着我们可以立即替换继承者4的节点3并将左子树连接到它,而不必首先将节点4移动到右子树的顶部:

      8                                 8
     / \                               / \
    3  ...                            4  ...
   / \                               / \
  2   4              4              2   6
 /     \              \            /   / \
1       6              6          1   5   7
       / \            / \         
      5   7          5   7        

此代码试图解释两种情况。第一种情况是删除一个节点X,该节点的继承者Y是其直接的右子节点:

X
 \
  Y
   \
    Z
在本例中,我们最终将用Y替换X,因此该方法可以返回Y并说“这是现在替换X的节点。”

另一方面,假设X的后继Y位于其右子树的子树中:

X
 \
  A
 / \
Y   C
 \
  B
在这种情况下,我们不能盲目地用Y替换X,因为这样做会丢失节点A和子树C中的所有内容。因此,在我们说“嘿,树-用节点Y替换节点X”之前,我们会重新排列树中的节点,使它们看起来像这样:

X
 \
  Y
   \
    A
   / \
  B   C
现在,当我们用Y替换X时,我们没有丢失树中的任何其他节点


顺便说一句,这里的形状是通过交换X和Y,然后删除X(这是在过去的点Y中)形成的通过使Y的前父级将Y的前右子树作为其左子级。通过这些行,看看您是否可以看到这是如何工作的。

自行解决这一问题的最简单方法是运行代码,并观察两者之间的差异。老实说,不必过于仔细地阅读核心,这看起来不像是一个问题ny normal“在二叉树中查找任何内容”实现,因为它会修改树。但是,一个八字树会通过将查询的节点移到树的顶部来修改树,但是问题中的代码也不足以做到这一点。@Carcigenicate这是真的!!我会尝试这么做。@RockySingh老实说,这是你应该尽可能做的第一件事(我不想听起来像是在说这个)。学习(在我看来)最好的方法就是乱搞代码。REPL非常适合这样做。