【问题标题】:Red Black Tree deletion of root红黑树删除根
【发布时间】:2016-08-03 18:09:56
【问题描述】:

除非我删除根,否则我的删除红黑树算法效果很好。只有一个孩子被保存,其余的树值都丢失了。

我相信问题出在removeNode() 方法中

if (remove == root)
{
    root = child;
} 

以下是用于删除的方法:

//Searching for value to remove
public void removeSearch(int value)
{
    RedBlackNode rt = root;
    while (rt != sentinel)
    {
        int compare = value.CompareTo(rt.getItem());
        if (compare == 0)
        {
            if (rt.getLeft() == sentinel || rt.getRight() == sentinel)
            {
                removeNode(rt);
            }
            else
            {
                RedBlackNode successor = inOrderSuccessor(rt);
                rt.setItem(successor.getItem());
                removeNode(rt);                        
            }
            return;
        }
        else
        {
            rt = rt.getChild(compare);
            //return true;
        }
    }
}

protected RedBlackNode inOrderSuccessor(RedBlackNode node)
{
    RedBlackNode descendant = node.getRight();

        while (descendant.getLeft() != sentinel)
        {
            descendant = descendant.getLeft();
        }
    return descendant;
}

protected void removeNode(RedBlackNode remove)
{
    count -= 1;
    RedBlackNode child;
    if (remove.getLeft() != sentinel)
    {
        child = remove.getLeft();
    }
    else
    {
        child = remove.getRight();
    }
    linkParentAndChild(remove.getParent(), child, comparison(remove, remove.getParent()));

    if(remove==root)
    {
        root = child;
    }
    if(remove.isBlack())
    {
        DeleteFix(child);
    }
}

protected void DeleteFix(RedBlackNode node)
{
    while((node!=root)&&(node.isBlack()))
    {
        RedBlackNode parent = node.getParent();
        int compare = comparison(node, parent);
        RedBlackNode sibling = parent.getChild(-compare);
        if(sibling.isRed())
        {
            sibling.setBlack();
            parent.setRed();
            rotate(-compare, parent);
            sibling = node.getParent().getChild(-compare);
        } 
        if(sibling.hasTwoBlackChildren())
        {
            sibling.setRed();
            node = node.getParent();
        }else
        {
            if(sibling.getChild(-compare).isBlack())
            {
                sibling.getChild(compare).setBlack();
                sibling.setRed();
                rotate(compare, sibling);
                sibling = parent.getChild(-compare);
            }
            sibling.setColour(parent.getColour());
            parent.setBlack();
            sibling.getChild(-compare).setBlack();
            rotate(-compare, parent);
            node = root;
        }
    }
    node.setBlack();
}

任何帮助都会很棒。谢谢

【问题讨论】:

    标签: c# algorithm data-structures binary-tree red-black-tree


    【解决方案1】:

    跟我一起来看看:

    if (remove.getLeft() != sentinel)
    {
        child = remove.getLeft();
    }
    else
    {
        child = remove.getRight();
    }
    linkParentAndChild(remove.getParent(), child, comparison(remove, remove.getParent()));
    
    if(remove==root)
    {
        root = child;
    }
    

    首先,假设remove == root。然后,假设根的左孩子是sentinel。第一个 if 分支的计算结果为 false,else 子句被执行,child 成为正确的节点。然后,您尝试获取根的父级(大概是null,但我不知道)并将其链接到正确的节点......我想这最终什么都不做,但我不确定因为你没有提供那个方法。然后,您将根替换为child,它是右节点,并且因为linkParentAndChild(可能)在null 中传递,所以没有办法恢复左节点,所以你破坏它并且它消失了。如果左侧节点不是sentinel,则过程完全相同,但您将保留左侧而不是右侧。

    希望这应该弄清楚它发生的原因。我不会告诉你如何解决它,原因有两个:

    1. 这几乎可以肯定是家庭作业,除非用于家庭作业,否则没有人会实现红黑树。
    2. 我不太记得红黑树的实现细节,主要是因为原因 1。

    祝你好运解决它!

    【讨论】:

    • 是的,事实上我错了,当我继续调试时,根总是不包括要删除的所选节点的右子树。这不仅发生在根部
    • 能否提供一些需要做什么的提示?我不确定我的方法是否遗漏了很多信息
    • 我对您的代码了解不多,无法帮助您进行广泛的调试,但听起来您与sentinel 的比较不起作用。如果您没有在RedBlackNode 上定义Equals() 方法,它将测试引用标识的相等性(我认为)所以除非您在任何地方使用完全相同的sentinel,否则比较可能不起作用。或者它可能是别的东西,我不知道。您最好(也更安全)与同学交谈或访问您的教师的办公时间。
    • 这已经解决了。第二天我对其进行了调试,并没有注意到我错过了另一个案例,即填充了左右孩子。添加了另一个方法findMinimum(),根的值根据返回值改变。