【问题标题】:recursive binary search tree remove method递归二叉搜索树删除方法
【发布时间】:2013-11-03 17:10:35
【问题描述】:

首先,这是作业,所以把它放在那里。

我应该用特定的方法实现一个二叉搜索树:

void insert(String)、boolean remove(String)、boolean find(String)。

我已经能够成功地编程和测试插入和查找方法,但在删除时遇到了困难。

我的程序中发生的事情是删除实际上并没有从树中删除任何东西,我相信这是因为它只引用了当前节点的本地创建,但我可能是错的。我想我可以实现我需要测试的不同案例的逻辑(可能需要帮助删除一个有两个孩子案例的节点,但我认为我在概念上得到了它)主要是想了解我需要做些什么来引用

中的正确树
current = null; // case

这是我目前得到的:

public boolean remove(String title)
{
    return remove(root, title);
}
private boolean remove(BSTNode current, String title)
{
    if (current == null)
    {
        return false;
    }
    if (current.data == title)
    {
    if (current.left_child !=null && current.right_child != null)
    {
        return true;  // returning true since I haven't finished writing this case
    }
    else if (current.left_child == null && current.right_child == null)
        {
        current = null;  // this should remove the node from tree but it doesn't
        return true; 
    }

    else if (current.left_child != null && current.right_child == null)
    {
        current = current.left_child;    // don't think this is right
        return true;
    }
    else if (current.right_child != null && current.left_child == null)
    {
        current = current.right_child;   // not sure about this
        return true;
    }

    }
root = current;
if (title.compareToIgnoreCase(current.data) == -1)
{
    return remove(current.left_child, title);
}
    else 
{
    return remove(current.right_child, title);
}
}

非常感谢任何知识。

【问题讨论】:

    标签: java recursion binary-search-tree


    【解决方案1】:

    一个节点被它的父节点引用(除了根节点,那个节点被你的 BST 本身引用)。为了从树中删除一个节点,您需要将父节点中的引用设置为null

    你现在想要做的事情是这样的:

    Before:
    parent.left ---> node <--- current
    
    After setting current = null:
    parent.left ---> node      current ---> null
    

    也就是说,当前引用 null,但这不会改变父级(只有那个局部变量)。

    在您的 remove 方法中,您还需要传递父级(或者在调用父级时处理两个子级,无论您更喜欢什么)。

    顺便说一句:从不将字符串与==进行比较,例如this question


    如何找到节点及其父节点没有在每个节点中显式存储父节点:

    我会说在循环中执行此操作比使用递归更简单,但两者都可以。在循环中:

    BSTNode parent = null;
    BSTNode current = root;
    boolean found = false;
    while (!found && current != null) {
        int compare = title.compareToIgnoreCase(current.data);
        if (compare == 0) {
            found = true;
        } else {
            parent = current;
            if (compare < 0) {
                current = current.left;
            } else {
                current = current.right;
            }
        }
    }
    if (!found) {
        // title was not found
    } else if (parent == null) {
        // found the root
    } else {
        // found another node
    }
    

    递归很烦人,因为你想要一个返回节点和它的父节点的方法。你需要一些简单的内部类来解决这个问题:

    private class NodeAndParent {
        public BSTNode node;
        public BSTNode parent;
        public NodeAndParent(BSTNode node, BSTNode parent) {
            this.node = node;
            this.parent = parent;
        }
    }
    
    private boolean find(String title, NodeAndParent current) {
        if (current.node == null) {
            return false; // not found
        } else {
            int compare = title.compareToIgnoreCase(current.node.data);
            if (compare == 0) {
                return true; // found
            } else {
                current.parent = current.node;
                if (compare < 0) {
                    current.node = current.node.left;
                } else {
                    current.node = current.node.right;
                }
            }
        }
    }
    
    private boolean remove(String title) {
        NodeAndParent nodeAndParent = new NodeAndParent(root, null);
        boolean found = find(title, nodeAndParent);
        if (!found) {
            // title was not found
        } else if (nodeAndParent.parent == null) {
            // found the root
        } else {
            // found another node
        }
    }    
    

    【讨论】:

    • 非常感谢您的反馈。你所描述的是我想象中的情况。我认为我的问题是我没有在类中定义父节点(讲师暗示这是一个不太优雅的解决方案,因此如果可以的话,请避免使用它)。我试图看看如何在不在插入方法中设置某种类型的引用的情况下告诉“当前”节点(基本情况 = 根)关于父级。我不认为这样的实现是可能的,因此我必须在插入中包含一个父节点以跟踪哪个节点是 current 的父节点,以便我可以更改其对 null 的引用。
    • @user2948847 实际上,您不应该在每个节点中存储父引用,这不是必需的。请参阅我关于如何查找节点及其父节点的更新。我会选择循环版本,但如果你必须使用递归,那就有点棘手了。您可以通过在我称为find 的方法中执行删除来摆脱内部类,但这违反了“关注点分离”的良好做法(单个方法不应同时找到节点并删除它)。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-08
    • 1970-01-01
    • 2014-04-19
    • 2013-11-21
    相关资源
    最近更新 更多