二叉树通过合并递归实现删除

时间:2014-02-27 18:59:08

标签: java recursion binary-tree

我已经通过合并实现了delete的迭代版本,但是我很难以递归的方式实现。

这是我的迭代版本:

public void deleteByMerging(T el) {
    BSTNode<T> tmp, node, p = root, prev = null;
    while (p != null && !p.el.equals(el)) {  
         prev = p;                           
         if (el.compareTo(p.el) < 0)
              p = p.right;
         else p = p.left;
    }
    node = p;
    if (p != null && p.el.equals(el)) {
         if (node.right == null) 
              node = node.left;  
         else if (node.left == null) 
              node = node.right; 
         else {                  
              tmp = node.left;   
              while (tmp.right != null) 
                  tmp = tmp.right;      
              tmp.right =        
                  node.right;    

              node = node.left;  
         }
         if (p == root)
              root = node;
         else if (prev.left == p)
              prev.left = node;
         else prev.right = node; // 5.
    }
    else if (root != null)
         System.out.println("el " + el + " is not in the tree");
    else System.out.println("the tree is empty");
}

现在我需要以这种方式实现递归函数:

public void delete(T info) {
    root = delete(root, info);
}

public TreeNode<T> delete(TreeNode<T> node, T info) 
    {

    }

我是递归的新手,我不知道从哪里开始。

1 个答案:

答案 0 :(得分:0)

(通过&#34;你的#34;迭代版本,你当然是指Adam Drozdek的。)

这应该有效:

public void delete(T info) {
    root = delete (root.info);
}

public TreeNode<T> delete(TreeNode<T> node, T info) {

    // if this node is null, we have reached the end of the tree
    // so the node is not in the tree.
    if (node == null) {
        return node; // or handle as required

    // if this is not the node to delete;
    // recursively call this on the node's correct child
    else if (info.compareTo(node.info) <0) {
        node.left = delete(node.left, info);
        return node;
    } else {
        node.right = delete(node.right, info);
        return node;
    }

    // if this is the node to delete:
    else if (node.info.equals(info)) {
        // to delete it, we must return a sub-tree without it.

        if (node.left == null) 
            // this node is a leaf node, or
            // node.right contains only child.
            // either way, return node.right
            return node.right;

        if (node.right == null) 
            // node.left contains only child
            return node.left;

        // else node has 2 children, so delete by merging:
        // first, find its direct predecessor:
        TreeNode<T> tmp = node.left;
        while (tmp.right != null)
            tmp = tmp.right;
        // then append the node's right sub-tree
        // to its direct predecessor:
        tmp.right = node.right;
        // lastly, replace the node by its left sub-tree:
        return node.left;
    }
}

首先我们检查node是否为空。如果是,那意味着我们要删除的元素不在树中,因为我们已遍历,直到我们用尽了所有节点。

接下来,我们检查元素是否大于或大于当前节点中的元素。如果是,我们需要继续遍历树,向左或向右移动,具体取决于元素的比较方式。请注意,在递归步骤中,我们将删除操作的结果分配给node个孩子中的一个。我们从第一个函数中获取了这个提示,其中root被分配了root上的删除操作的结果。这将递归遍历树,直到node引用您要删除的节点。我们还在这里返回node,这样如果没有发生任何更改,例如,对node.right = delete(node.right, info)的调用将不会更改当前节点。

当我们找到节点时,可能有4种情况:节点可以是叶子节点(没有子节点),或者它可以有1个左子节点或1个右子节点,或者它可以有2个子节点。第3个场景由行

涵盖
if (node.left == null)
    return node.right;
if (node.right == null)
    return node.left;

请注意,如果node没有孩子,则第一次if检查将为真,因此将返回node的右子(null)节点。

为什么返回null删除节点?因为,在上面讨论的遍历步骤中,我们将删除操作的结果分配给node的孩子。请注意,在此步骤中,前一个递归步骤中的nodenode的父级,因为删除是在该节点的子级上递归调用的。因此,在此处返回null将导致先前的调用将null分配给父的子节点,从而删除子节点。基本上,每当我们返回除node以外的任何内容时,我们将用树中返回的任何内容替换当前节点。

在第四种情况下,我们需要通过合并进行简单的删除。您可以通过将node的右子树附加到其左子树中最右边的节点来实现。首先,我们在左子树中找到最右边的节点,它是node的直接前身:

TreeNode<T> tmp = node.left;
while (tmp.right != null)
    tmp = tmp.right;

所以tmp现在是node的直接前任。接下来,我们将node的右子树锁定到tmp

tmp.right = node.right;

最后,要将node替换为左侧子树,我们只需返回node.left,因为这会将node替换为node.left作为node的子项1}}在前一个递归调用中的父级。

如果我的解释让您感到困惑,可以试试this one。这更容易用纸上的图片来解释,这就是为什么你应该在实际课程中问我(是的,我设置了这个实践)而不是SO :)希望你在截止日期之前弄清楚它!