【问题标题】:Red black trees implementation红黑树实现
【发布时间】:2021-08-11 19:46:33
【问题描述】:

我正在尝试为红黑树实现插入操作。我用 C++ 编写了这个名为 RedBlack 的类,其中包含如下插入函数:

    void RedBlack::Insert(int data)
    {
        printf("init !!!\n");
        ColoredNode* myIterator = this->root ; // will iterate throw the tree until it reachs the centinel ;
        ColoredNode* IteratorParent = this->centinel ; // will store the parent of myIterator 
        ColoredNode* newNode = new ColoredNode(this->centinel,data,false);  
        
        printf("insert %d ------\n",data);
    
        while(myIterator != this->centinel)
        {
            printf("in While Loop node = %d-----------\n",myIterator->data);
            IteratorParent = myIterator ;
            if(data > myIterator->data)
                myIterator = myIterator->right;
            else
                myIterator = myIterator->left;
        }
    
        newNode->parent = IteratorParent ;
    
        if(IteratorParent == this->centinel)
            this->root = newNode ;
        else if (data >= IteratorParent->data)
            IteratorParent->right = newNode ;
        else
            IteratorParent->left = newNode ;
            
        this->InsertFixUp(newNode);
        myIterator = newNode = IteratorParent = nullptr ;
    }





void RedBlack::InsertFixUp(ColoredNode* node)
{
    /*
    * Here We Have Three Cases :
    *   -> Uncle Is Red ==> parent , Uncle will be Black and GrandParent will be Red 
    *   ->Uncle Is Black here we Have 2 cases :(suppose that Uncle Is right Child of Its Parent)
    *       -> if node Is right => LeftRotation
    *       -> if node Is Left => grandParent rightRotation
    *       and the same approach if Uncle Is left 
    */   

    ColoredNode* parent = nullptr ;
    ColoredNode* grandParent = nullptr ;
    ColoredNode* uncle = nullptr ;

    while(node != this->centinel && node->parent->isRed())
    {
        parent = node->parent ;
        grandParent = parent ->parent ;
        
        if(grandParent -> left == parent )
        {
            uncle = grandParent -> right;
            if(uncle->isRed())      // Case 1 : color both parent and uncle black 
            {
                parent -> black = true;
                uncle  -> black = true;
                grandParent->black = false ;
                node = grandParent ;
                continue ;
            }
            else if(node == parent->right)
            {
                this->LeftRotation(parent);
                node = parent ;
                parent = parent->parent ;
            }
            parent->black = true ;
            //node -> black = false;
            grandParent ->black = false ;
            RightRotation(grandParent);
            
        }
        else                    //Other side 
        {
            uncle = grandParent -> left;
            if(uncle -> isRed())
            {
                parent -> black = true ;
                uncle -> black = true ;
                grandParent -> black = false;
                node = grandParent ;
                continue;
            }
            else if (node == parent->left)
            {
                RightRotation(parent);
                node = parent;
                parent = parent-> parent;
            }
            parent -> black = true ;
            grandParent-> black = false;
            LeftRotation(grandParent);
        }
    }

}

这是代表节点的结构

struct ColoredNode
{
    ColoredNode *parent , *right , *left ;
    int data ;
    bool black ;
    ColoredNode(ColoredNode *node,int data,bool blackness)
    {
        right = left = parent = node ;
        this->data = data ;
        this->black = blackness;
    }

    bool isBlack()
    {
        return black;
    }

    bool isRed()
    {
        return !black;
    }
};

问题是我的插入不起作用,我猜“继续”语句会产生程序进入 InsertFixUp 并且没有退出的问题,

【问题讨论】:

标签: c++ algorithm data-structures


【解决方案1】:

我不想这么说,但是 RB 插入很粗糙,等到你删除!啊!

如果我没记错我的 CS,根节点应该总是黑色的,红色节点不应该有一个红色节点作为子节点。新节点应该是红色的。然后在检测到违规后,旋转树并重新着色以保持此不变性。

在我自己实现了一个 RB 树和一个 AVL 树之后,在经历了很多痛苦之后,我强烈建议从一棵空树开始,然后对你的算法进行桌面检查。首先保持算法简单。忽略未处理的错误情况,只检查它是否适用于简单的情况。通过它运行一些示例树后,您可以稍后添加更多案例。这可以在根本不编码的情况下完成,并将帮助您了解它是如何工作的。一旦完成,编写代码应该会更简单。但是,当您在学习新语言的同时学习 RB 树的工作原理时,确实会受到伤害。

首先要测试您的旋转算法是否有效,因为其他一切都取决于此。

【讨论】:

  • 是的,你说得对,我要测试