当前位置: 首页 > 知识库问答 >
问题:

这是BST Hibbard删除错误的代码吗?

闾丘昊然
2023-03-14

我正在读普林斯顿大学的Sedgewick和Wayne写的《算法》一书,它为BSTMaps提供了一种BST删除方法。

public void deleteMin()
{
    root = deleteMin(root);
}

private Node deleteMin(Node x)
{
    if (x.left == null) return x.right;
    x.left = deleteMin(x.left);
    x.N = size(x.left) + size(x.right) + 1;
    return x;
}

public void delete(Key key)
{
    root = delete(root, key);
}

private Node delete(Node x, Key key)
{
    if (x == null) return null;
    int cmp = key.compareTo(x.key);
    if (cmp < 0) x.left = delete(x.left, key);
    else if (cmp > 0) x.right = delete(x.right, key);
    else
    {
        if (x.right == null) return x.left;
        if (x.left == null) return x.right;
        Node t = x;
        x = min(t.right); // <----This would cause infinite loop
        x.right = deleteMin(t.right);
        x.left = t.left;
    }
    x.N = size(x.left) + size(x.right) + 1;
    return x;
}

原来是一个著名的算法,叫做急切希伯德删除,也在这个环节中呈现。

由于代码是用Java编写的,所以我尝试自己实现它。但由于引用问题,它会导致无限循环。如果x指向后续节点,并且x.left被更新,那么deleteMin方法不仅会删除原始节点,还会通过新的左分支删除树的另一半的最小值。

这可以通过复制min(t.right)的值和键来绕过,而不只是使用“=”,并且不需要t节点。

但我的问题是:这本书(和网页)中的代码是否完全错了?很难想象,因为这是一本第四版的畅销书。

下面的示例再现了这个问题。

BSTMap<String, Integer> bstmap = new BSTMap<>();
bstmap.put("hello", 5);
bstmap.put("cat", 10);
bstmap.put("fish", 22);
bstmap.put("zebra", 90);
Integer rm = bstmap.remove("dog");
Integer rm2 = bstmap.remove("hello");

这棵树原来是:

       ┌────────┐
    ┌──┤ hello  ├────────┐
    │  └────────┘        │
    │                    │
 ┌──┴───┐            ┌───┴────┐
 │ cat  ├─┐          │ zebra  │
 └──────┘ │          └────────┘
      ┌───┴───┐
      │ fish  │
      └───────┘

删除(我代码中的“删除”)应该在删除“Hello”时促进“zebra”。但是在将“zebra”.↓分配给“cat”后,deleteMin方法会删除“cat”而不是“zebra”本身,导致“zebra”指向自己。

共有1个答案

孙阳旭
2023-03-14

不,Sedgewick和Wayne代码没有错。我绝对喜欢这本书,但有时它的代码对我的口味来说有点蹩脚。在他们的实现中,他们希望跟踪每个节点的“大小”,因此他们调用deleteMin(...)来重新计算这个属性。他们对min(...)的实现也是正确的,因为这种方法递归地找到从根节点开始的具有最小键的节点。我将复制我的Hibdard删除实现并附上一些注释。如果我的实现无法工作,可能您在构建BST的方式上存在问题。

public void delete( Key key ) throws IllegalArgumentException {

    if ( key == null ) {
        throw new IllegalArgumentException( "argument to delete() is null" );
    }
    
    root = delete( root, key );

}

private Node delete( Node node, Key key ) {
    
    if ( node != null ) {
        
        Node temp;
        int comp = key.compareTo( node.key );

        // found the node with the key to remove
        if ( comp == 0 ) {
            
            size--;  // symtable size
            
            // the node does not have any childrem
            // so, in it's place it will be a 
            // null reference
            if ( node.left == node.right ) {

                return null;

            // the node does not have a left child
            // the node that will replace it will
            // be its right child
            } else if ( node.left == null ) {

                temp = node.right;
                node.right = null;
                return temp;

            // the node does not have a right child
            // the node that will replace it will
            // be its left child
            } else if ( node.right == null ) {

                temp = node.left;
                node.left = null;
                return temp;

            // the node have left and right childrem
            } else {

                // marks the node that will replace the removed node
                temp = node.right;
                
                // marks the same node to perform the search
                // for the minimal node
                Node min = temp;

                // searches for the minimal node
                while ( min.left != null ) {
                    min = min.left;
                }
                
                // the left subtree of the node that will
                // be removed is now the left subtree of the
                // minimal node
                min.left = node.left;

                // detaches the left and right subtrees of the
                // node that will be deleted
                node.left = null;
                node.right = null;

                // return the node that was greater than the 
                // node that was removed
                return temp;

            }

        } else if ( comp < 0 ) {
            node.left = delete( node.left, key );
        } else { // comp > 0
            node.right = delete( node.right, key );
        }
        
    }
    
    return node;

}
 类似资料:
  • 将“const IntBag”作为“this”参数传递将丢弃限定符[-fppermissive] 这是我的代码:''C'** ** 我的错误是:$g intbag。cpp intbag。cpp:复制构造函数的IntBag::IntBag(const IntBag) 在此处输入图像描述

  • 您好,我正在尝试在我的Web服务中运行一个查询,但是一个查询在范围内的函数会从零开始中断。 我的代码: 错误: 获取请求失败请求失败-- 类型异常报告 Message内部服务器错误 描述服务器遇到内部错误,无法满足此请求。 例外 javax.servlet.ServletException:java.lang.NullPointerException 根本原因 JAVAlang.NullPoint

  • 问题内容: 我正在尝试为Java创建一个小的功能性编程库(只是为了解决自己的问题)。虽然定义高阶函数为S,S和就是我所遇到的这个问题:需要收集的功能,并返回相同类型的具有几乎相同的实现的集合,但必须重新界定为每个数据结构-s,s和s。 例如,这是s和s 的函数的实现: 一个函数: 如从这个例子可以看出,对于实施方式中的主体和几乎相同。 有喜欢很多很多的功能,并在我的图书馆,每一类又是对每种类型我很

  • 这篇教程探索了更好的理解代码基础、寻找并修复bug的工具。 这部分内容并不是特别针对于科学Python社区,但是我们将要采用的策略是专门针对科学计算量身定制的。 先决条件 Numpy IPython nosetests (http://readthedocs.org/docs/nose/en/latest/) pyflakes (http://pypi.python.org/pypi/pyflak

  • 我在路径中编辑pic文件并为其创建新的图像文件。我的代码是: 怎么修?

  • 我在使用elasticsearch dsl删除项目时遇到问题。当我试图过滤我的数据时,它很容易,像这样的东西效果很好。 扫描也可以: 但是当我想删除这样的项目时: 我出错了: