为什么此代码中的此行必须从BST中删除?

时间:2017-08-12 21:17:44

标签: algorithm data-structures binary-search-tree

我试图了解有关二叉树的更多信息,并且我遇到了一个关于如何找到后继节点的方法(当尝试删除节点时),我很难理解其中的一部分。 这是代码。

    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语句是必要的?

2 个答案:

答案 0 :(得分:1)

getSuccessor()所做的是找到delNode的后继者,delNode是具有大于delNode的最小值的节点,即delNode下右子树中最左边的节点。然后它将其从右侧子树中删除,并将右侧子树附加到后继项下的右侧。

条件的原因是如果后继者是delNode的右子,它已经位于右子树的顶部,并且不需要从子树中取出并移动到顶部它。

在下一步中,delNode将被删除,后继将附加到delNode的父级,delNode下的左子树将附加到后继的左侧。所有这一切的效果是将delNote替换为其继任者。

(此方法不是从二叉树中删除节点的最简单方法。您可以简单地将右子树附加到delNode的父节点,将左子节点附加到左侧的后续节点。但这种更复杂的方法具有不增加树高度的优点,因为每个节点都保持在相同的深度,或者移动到更靠近根的位置。)

这是一个我们要删除节点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        

答案 1 :(得分:1)

此代码试图考虑两种情况。第一个是你要删除其继承者Y是其直接右子的节点X:

X
 \
  Y
   \
    Z

在这种情况下,我们最终将用Y替换X,因此该方法可以返回Y并说出&#34;这里是现在替换X的节点。&#34; < / p>

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

X
 \
  A
 / \
Y   C
 \
  B

在这种情况下,我们不能盲目地用Y替换X,因为这样做会丢失节点A和子树C中的所有内容。所以在我们说&#34; hey tree之前 - 用节点替换节点X Y,&#34;我们重新排列树中的节点,使它们看起来像这样:

X
 \
  Y
   \
    A
   / \
  B   C

现在,当我们用Y替换X时,我们还没有丢失树中的任何其他节点。

顺便说一下,这里的形状是通过交换X和Y形成的,然后通过让Y的前任父母拥有Y的前者来删除X(在Y中曾经存在的地方)右子树为其左子。跟踪这些行,看看你是否能看到它是如何工作的。