【问题标题】:Removing leaves from Binary Tree not being represented properly从没有正确表示的二叉树中删除叶子
【发布时间】:2015-07-05 22:29:42
【问题描述】:

我一直致力于从头开始创建二叉树,而不是使用内置库。我正在研究一个名为“pruneLeaves”的函数。工作是去除树上的所有叶子;没有子节点的节点。

当我通过断点单步执行函数时,它似乎正在移除叶子,甚至打印出它确实正在移除正确的节点。但是,当我之后在 main 函数中显示树时,节点仍然存在!

我已经尝试了几个小时来解决这个问题,我忽略了什么?!

程序输出:

Num nodes = 9
Pruning.
12
Leaf removed
9
Leaf removed
4
Leaf removed
Tree after pruning..
3 4 5 6 7 8 9 11 12 

    // Recursive helper. Accepts BinaryNode as a parameter
private BinaryNode pruneLeaves(BinaryNode t) {

    // If we have no left child AND no right child, we are a leaf
    if ((t.left == null) && (t.right == null)) {

        //Print the element being removed.
        System.out.println (t.element);

        //Remove the element
        t = remove(t.element, t);

        if(t == null)
            System.out.println("Leaf removed");
    }
    // Else we have at least one child
    else {

        if (t.right != null) {
            pruneLeaves(t.right);
        }

        if (t.left != null) {
            pruneLeaves(t.left);
        }
    }
  //Return our leafless tree
  return t;
}

// Main recursive method, call the helper method by passing the root of the 
// tree, which calls it.
public void pruneLeaves () {
    pruneLeaves(this.getRoot());
}

BinaryNode getRoot () {
    return this.root;
}

/**
 * Internal method to remove from a subtree.
 * @param x the item to remove.
 * @param t the node that roots the tree.
 * @return the new root.
 */
private BinaryNode remove( int x, BinaryNode t )  {
success = false;
    if( t == null )
        return t;   // Item not found; do nothing

    if( x < t.element )
        t.left = remove( x, t.left );

    else if( x > t.element )
        t.right = remove( x, t.right );

    else {
        success = true;

        if( t.left != null && t.right != null )  { // Two children
            t.element = findMin( t.right ).element;
            t.right = remove( t.element, t.right );
        }

        else
        t = ( t.left != null ) ? t.left : t.right;
    }
    return t;
}

还有我的main方法,调用函数:

    public static void main( String [ ] args )   {
    BST t = new BST( );

    t.insert(7);
    t.insert(6);
    t.insert(5);
    t.insert(3);
    t.insert(4);
    t.insert(8);
    t.insert(11);
    t.insert(9);
    t.insert(12);

    System.out.println();
    System.out.println ("Num nodes = " + t.countNodes());
    System.out.println ("Pruning.");

    // Remove leaves of the tree
    t.pruneLeaves();
    t.infix();
    System.out.println();
}

【问题讨论】:

  • remove()方法的内容是什么?
  • 在我看来,整个删除功能毫无意义。您使用参数 t.element 和 t 调用 remove。因此,将 t.element 与 x 进行比较的 if 语句将始终落入最后一个 else 语句。您的 t.left 和 t.right 将始终为 null,因此您的 remove 将始终返回 null。因此,这将问题更改为“为什么设置 t = null 不会改变 BST?”
  • @BoldAsLove,你完全正确。这是一个毫无意义的电话,在网站上进行了更多搜索后,我找到了解决我问题的答案。

标签: java binary-tree


【解决方案1】:

使用链接:Deleting Leaves From a Binary Tree

我在我的代码中发现了错误,并使用链接中给出的答案进行了更正。

正确代码如下:

private BinaryNode pruneLeaves (BinaryNode p) {

    // There is a left child
    if (p.left != null)
        if (isLeaf(p.left)) //Is that child a leaf?
            p.left = null;             
        else
            pruneLeaves(p.left);      // If it is not, recursive call

    // Is there a right child
    if (p.right != null)
        if (isLeaf(p.right))
            p.right = null;            
        else
            pruneLeaves(p.right);     // Recursive call
    return p;
}

// Main recursive call, passes the root of calling tree to the helper method
public void pruneLeaves () {
    pruneLeaves (this.getRoot());
}

// Returns true if child is a leaf
boolean isLeaf (BinaryNode t) {
    if (t.left == null && t.right == null) {
        return true;
    }
    return false;
}

【讨论】:

  • 这是答案,但 IMO 重要的是要注意您的方法不起作用的原因是由于误解了您设置为 null 的内容。您正在设置对 null 的引用,而不是实际的节点。
  • 但是如果我删除对节点的引用,它不会被垃圾收集器拾取吗?
  • 是的,如果你删除了对parent节点中的节点的引用并且没有其他引用存在,那么它将被拾取。该方法所做的是将本地引用设置为 null,这根本不会影响父节点中的引用。上面发布的修复现在将父节点中的引用设置为 null,这是正确的。
【解决方案2】:

+1 是正确的答案(到目前为止我只找到了一个),但是您忘记了根的 null 场景,并且如果根本身没有子级,则还要删除根。我是这样做的——我使用了你的代码,然后确保它适合所有场景:

public void removeLeaves () {
    if (root != null) {
        removeLeaves (root);
    } else {
        return;
    }
}

private Node removeLeaves (Node node) {
    if (root.left == null && root.right == null) {
        root = null;
    } else {
        if (node.left != null) {
            if (node.left.left == null && node.left.right == null) {
                node.left = null;             
            } else {
                removeLeaves(node.left);
            }
        }
        if (node.right != null) {
            if (node.right.left == null && node.right.right == null) {
                node.right = null;      
            } else {
                removeLeaves(node.right);     
            }
        }
    }
    return node;
}

这段代码确保所有没有子节点的节点都被删除,同时也消除了对 isLeaf() 函数的需要。

【讨论】:

  • 感谢您的更新和修复!感谢您花时间和精力在此发布!我会更新我的旧代码:)
猜你喜欢
  • 1970-01-01
  • 2018-10-22
  • 2018-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多