二叉树:方法删除子树

时间:2012-10-31 18:00:13

标签: java binary-tree

我有一个无序的二叉树,我不得不做一个删除根x的子树的方法。如果元素x在二叉树中多次出现,则该方法仅删除根x中的一个子树(它找到的第一个子树)。如果执行了删除,则返回true。如果元素x不存在于二叉树中,则返回false。所以方法是:

    public class BinaryTree 
{
    protected class Node 
    {
        Integer element;
        Node left;
        Node right;

        Node(int element) 
        {
            this.element = element;
            left = right = null;
        }

        Node(int element, Node left, Node right) 
        {
            this.element = element;
            this.left = left;
            this.right = right;
        }

    protected Node root;

    public BinaryTree() 
    {
        root = null;
    }

    private class BoolNode 
    {
        boolean ft;
        Node nodo;

        BoolNode(boolean ft, Node nodo) 
        {
            this.ft = ft;
            this.nodo = nodo;
        }
    }

    public boolean removeSubtree(int x) 
    {
        BoolNode ris = removeSubtree(x, root);
        //root = ...;
        return ris.ft;
    }

    private BoolNode removeSubtree(int x, Node node) 
    {
        return null;
    }
}

我不知道如何开始,有没有人有任何想法?甚至伪代码.. 谢谢!

3 个答案:

答案 0 :(得分:3)

应该是这样的......

  • 查找包含值X的节点N
  • 如果N是叶子,则移除叶子
  • 如果N是父母,

     removeNodes(N.left);
     removeNodes(N.right);
     remove(N);
    
  • 重复,直到你落叶

     private void removeNodes(Node base);  //prepare for this when the teacher asks you why it's private
     // - because you do not want to expose this functionality outside of the class;
     // the only 'interface' exposed is the wrapper call removeSubtree(...) as the user shouldn't worry about the internal functionality.
    

removeSubtree()是递归removeNodes();

的包装器 编辑:好的,以澄清你的错误。假设我们有这棵树

             1 --- this is root
            / \
           3   7
          / \ / \
     (a) 5  4 3  2  //these branches don't matter right now
        / \
       5   6
      / \  / \
     5  4 3   2

现在,假设您调用removeSubtree(5,root);

它将遍历树,直到它到达节点(a) - 左边的前5个。 编写当前代码的方式是:它将找到值为X(5)的节点;然后,对于他所有的左右子孙,它将寻找值5.

让我们关注这个

             1 --- this is root
            / \
           3   7
            \ / \
            4 3  2  

这是调用removeSubtree(5,root)后应该得到的;换句话说,查找在找到值为5的第一个节点并删除它的子节点后应该删除的子树

         5  -- we should delete all of these starting from here
        / \
       5   6
      / \  / \
     5  4 3   2

但是您的代码随后会在该子树中查找要删除的值5。这就是为什么你需要一个通用的deleteSubtree()例程,它将遍历树并删除它找到的所有内容。您的removeSubtree(int,node)例程必须通过实现该机制本身来依赖它或“内联”它。

现在您的代码只会删除此

             1 --- this is root
            / \
           3   7
          / \ / \
     (a) 5  4 3  2  //these branches don't matter right now
        / \
  (b)  5   6
      / \  / \
(c)  5  4 3   2

换句话说,它将落在节点A(前5个)上,而不是删除节点(a)下面的所有内容,它将搜索低于A的另一个值5,找到(b)并尝试删除它的子树,仅匹配节点(c)。

最终结果将是 - 您的代码将只删除三个五,并留下您的

             1 --- this is root
            / \
           3   7
          / \ / \
         x  4 3  2  
        / \
       x   6
      / \  / \
     x  4 3   2

您现在意识到为什么不能递归使用相同的功能吗? :)至少不是你现在想要的方式。但是,你可以尝试这个 -

 removeSubtree(node.left.value, node);
 removeSubtree(node.right.value, node);
 removeNode(node);

这将有效地找到正确的子树 - 节点(a),然后调用自身以匹配它的子节点 - 节点5和6(节点(b)的深度),从而删除它们。在任何情况下,您都不能像以前那样在

中重复使用值X.
 removeSubtree(x, node.left);
 removeSubtree(x, node.right);
 removeNode(node);

我希望澄清一些东西:)嘿,也许我应该教这个:D

答案 1 :(得分:0)

我改写了这个方法。现在我认为它更正确,但我认为指令node.left = null存在问题(与右侧情况相同)。事实上,当我去运行时,这种方法无法正常工作,如果我有一棵树就这样做了 enter image description here 我传递x = 8,它返回这棵树 enter image description here

答案 2 :(得分:0)

    private BoolNode removeSubtree(Node node, int x) 
{
    if(node == null) 
        return new BoolNode(false, null);
    if(node.element == x) 
        return new BoolNode(true, null);
    BoolNode result = removeSubtree(node.left, x);
    if(result.fatto)
        node.left = null;
    else {
        result = removeSubtree(node.right, x);
        node.right = null;  
    }
    return new BoolNode(result.fatto, node);    
}