【问题标题】:Red Black Tree Insert Issue红黑树插入问题
【发布时间】:2011-08-06 15:43:28
【问题描述】:

我是红黑树的新手,我遇到了这个问题的根源。旋转和插入方法看起来是正确的。但是,当我输入数字时 100 45 34 55 74 50 130 120 125 160 165 150

我从程序中得到以下输出。最右边的数字是节点中的数字,然后是颜色,然后是节点的父节点。根节点没有列出父节点。节点 45 和 74 都是 RED 并且这两个节点不能都是红色的,因为这违反了 RED Black Tree 属性:红色的父母总是有两个黑色的孩子。在这个问题上的任何帮助都会很棒。

34 [BLACK] (45)

45 [RED] (74)

50 [RED] (55)

55 [BLACK] (45)

74 [RED] (120)

100 [BLACK] (74)

120 [BLACK]

125 [BLACK] (130)

130 [RED] (120)

150 [RED] (160)

160 [BLACK] (130)

165 [RED] (160)

红黑树.h /*

#ifndef RBTREE
#define RBTREE
#include <iostream>
#include "nodes.h"
#include "BinarySearchTree.h"
using namespace std;

/*
 * RedBlackTree
 *
 * Class defination of RedBlackTree.
 *
 * This class represents a Red Black Tree data structure where the data is to be 
 * stored in a node. It is extended from BinarySearchTree.h
 *
 * @see BinarySearchTree.h, nodes.h
 *
 */
class RedBlackTree : protected BST
{
private:
    //RBTreeNode *root;
    bool rotateLeft(RBTreeNode *);
    bool rotateRight(RBTreeNode *);
    bool insertFix(RBTreeNode *);
    bool delFix(RBTreeNode *);
    void recurseDisplay(RBTreeNode *);
    RBTreeNode * findNode(int);

public:
    RedBlackTree();
    bool insert(int); 
    void display(); 
    bool del(int); 
    RBTreeNode * successor(int); 
    RBTreeNode * getRoot();
    void setRoot(RBTreeNode *);
    ~RedBlackTree();
};
#endif

红黑树.cpp BST::insert(rbnode) 函数适用于此类,因为函数中的差异是在使用其他函数之前完成的。

#include <iostream>
#include "RedBlackTree.h"

using namespace std;

#define RED 1
#define BLACK 2


/*
 * Constructor
 */
RedBlackTree::RedBlackTree(){
    setRoot(NULL);
}

/*
 * Destructor
 */
RedBlackTree::~RedBlackTree(){


    while(getRoot() != NULL){
        del(getRoot()->word);
    }
}

/*
 * get the root
 */
RBTreeNode * RedBlackTree::getRoot(){
    return static_cast<RBTreeNode *>(BST::getRoot());
}

/*
 * set the root
 */
void RedBlackTree::setRoot(RBTreeNode *rootin){
    BST::setRoot(rootin);
}

/* 
 * Inserts the string into the tree. 
 *
 * @param   String      The string to add to the tree
 * @return  False       if already in the tree
 */
bool RedBlackTree::insert(int word){

    RBTreeNode *rbnode = new RBTreeNode;

    rbnode->color = RED;
    rbnode->word = word;
    rbnode->setLeft(NULL);
    rbnode->setRight(NULL);

    if(BST::insert(rbnode)){
        insertFix(rbnode);
        return true;
    }else{
        delete rbnode;
        return false;
    }

}


/* 
 * Display the items in a tree in order and with color
 *
 * @param   RBTreeNode  The next node to recurse on
 */
void RedBlackTree::recurseDisplay(RBTreeNode *node){

    if(node != NULL){
        recurseDisplay(node->getLeft());
        cout<<node->word<<"";
        cout<<" [";
        if(node->color == RED){cout<<"RED";}
        if(node->color == BLACK){cout<<"BLACK";}
        cout<<"] ";

        if(node->getParent() != NULL){
            cout << "(" << node->getParent()->word<<")\n";
        }else{
            cout<<"\n";
        }

        recurseDisplay(node->getRight());

    }
    return;
}

/* 
 * Display the items in a tree in order
 *
 */
void RedBlackTree::display(){

    recurseDisplay(getRoot());

    return;
}

/* Delete a word from the tree
 * 
 * @param   string  The string to delete
 * @return  bool    False if it does not exist in tree
 */
bool RedBlackTree::del(int word){

    RBTreeNode *x, *y, *z;

    z = findNode(word);

    if(z == NULL){
        return false;
    }

    if((z->getLeft() == NULL) || (z->getRight() == NULL)){
        y = z;
    }else{
        y = successor(z->word);
    }

    if((y != NULL) && (y->getLeft() != NULL)){
        x = y->getLeft();
    }else if(y != NULL){
        x = y->getRight();
    }

    if((y != NULL) && (y->color == BLACK)){

        delFix(x);
    }

    return BST::del(word);
}

/* 
 * Search for the successor of a string and return it if in tree
 *
 * @param   String      The string whose successor to search for
 * @return  RBTreeNode  if string in the tree else return null
 */
RBTreeNode * RedBlackTree::successor(int word){
    TreeNode *tnode;
    tnode = BST::successor(word);
    return static_cast<RBTreeNode *>(tnode);
}

bool RedBlackTree::rotateLeft(RBTreeNode *node_x){

    RBTreeNode *node_y;

    if(node_x->getRight() == NULL){
        return false;
    }

    node_y = node_x->getRight();

    if(node_y->getLeft() != NULL){
        node_y->getLeft()->setParent(node_x);
        node_x->setRight(node_y->getLeft());
    }

    node_y->setParent(node_x->getParent());

    if(node_x->getParent() == NULL){
        setRoot(node_y);
    }else if(node_x == node_x->getParent()->getLeft()){
        node_x->getParent()->setLeft(node_y);
    }else{
        node_x->getParent()->setRight(node_y);
    }

    node_x->setRight(node_y->getLeft());
    node_y->setLeft(node_x);
    node_x->setParent(node_y);

    return true;
}

/* 
 * Rotate the tree right on y
 *
 * @param   RBTreeNode  The node to rotate on
 * @return  False       if node to ret on deos not exist
 */
bool RedBlackTree::rotateRight(RBTreeNode *node_y){

    RBTreeNode *node_x;

    if(node_y->getLeft() == NULL){
        return false;
    }

    node_x = node_y->getLeft();

    if(node_x->getRight() != NULL){
        node_x->getRight()->setParent(node_y);
        node_y->setLeft(node_x->getRight());
    }

    node_x->setParent(node_y->getParent());

    if(node_y->getParent() == NULL){
        setRoot(node_x);
    }else if(node_y == node_y->getParent()->getLeft()){
        node_y->getParent()->setLeft(node_x);
    }else{
        node_y->getParent()->setRight(node_x);
    }

    node_y->setLeft(node_x->getRight());
    node_x->setRight(node_y);
    node_y->setParent(node_x);

    return true;
}

/* 
 * Maintains the red black tree properties after a node is deleted
 *
 * @param   RBTreeNode  The node that is in violation
 * @return  true        always
 */
bool RedBlackTree::delFix(RBTreeNode *nodein){

    RBTreeNode *x, *w;
    x = nodein;

    while( x != getRoot() && x != NULL && x->color == BLACK){

        if(x->getParent()->getLeft() == x){

            w = x->getParent()->getRight();


            if(w != NULL && w->color == RED){
                w->color = BLACK;
                x->getParent()->color = RED;
                rotateLeft(x->getParent());
                w = x->getParent()->getRight();
            }

            if((w != NULL && w->getLeft() != NULL) && 
                            (w->getLeft()->color == BLACK) && 
                            (w->getRight() && w->getRight()->color == BLACK)){

                w->color = RED;
                x = x->getParent();

            }else if(w != NULL && w->getRight()->color == BLACK){

                w->getLeft()->color = BLACK;
                w->color = RED;
                rotateRight(w);
                w = x->getParent()->getRight();
            }

            if((w != NULL) && (x->getParent() != NULL)){
                w->color = x->getParent()->color;
            }

            if(x->getParent() != NULL){
                x->getParent()->color = BLACK;
            }

            if(w != NULL && w->getRight() != NULL){
                w->getRight()->color = BLACK;
            }

            rotateLeft(x->getParent());
            x = getRoot();

        }else{

            w = x->getParent()->getLeft();

            if((w != NULL) && (w->color == RED)){
                w->color = BLACK;
                x->getParent()->color = RED;
                rotateRight(x->getParent());
                w = x->getParent()->getLeft();
            }

            if(w != NULL){
                if((w->getRight()->color == BLACK) && 
                   (w->getLeft()->color == BLACK)){

                    w->color = RED;
                    x = x->getParent();

                }else if(w->getLeft()->color == BLACK){

                    w->getRight()->color = BLACK;
                    w->color = RED;
                    rotateLeft(w);
                    w = x->getParent()->getLeft();
                }
            }
            if(w !=NULL){
                w->color = x->getParent()->color;
                w->getLeft()->color = BLACK;
            }

            if(x != NULL && x->getParent() != NULL){
                x->getParent()->color = BLACK;
                rotateRight(x->getParent());
            }
            x = getRoot();

        }
    }
    if(x != NULL){
        x->color = BLACK;
    }


    return true;

}

/* 
 * Maintains the red black tree properties after a node is inserted
 *
 * @param   RBTreeNode  The node that is in violation
 * @return  true        always
 */
bool RedBlackTree::insertFix(RBTreeNode *nodein){

    RBTreeNode *y, *z;
    z = nodein;

    while((z->getParent() !=NULL) && z->getParent()->color == RED){ 
        if((z->getParent() != NULL) && 
           (z->getParent() == z->getParent()->getParent()->getLeft())){

            y = z->getParent()->getParent()->getRight();

            if((y != NULL) && (y->color == RED)){

                z->getParent()->color = BLACK;
                y->color = BLACK;
                z->getParent()->getParent()->color = RED;
                z = z->getParent()->getParent();

            }else if(z == z->getParent()->getRight()){

                z = z->getParent();
                rotateLeft(z);

            }

            if(z->getParent() != NULL){

                z->getParent()->color = BLACK;

                if(z->getParent()->getParent() != NULL){

                    z->getParent()->getParent()->color = RED;
                    rotateRight(z->getParent()->getParent());
                }
            }

        }else if(z->getParent() == z->getParent()->getParent()->getRight()){

            y = z->getParent()->getParent()->getLeft();

            if((y != NULL) && (y->color == RED)){

                z->getParent()->color = BLACK;
                y->color = BLACK;
                z->getParent()->getParent()->color = RED;
                z = z->getParent()->getParent();

            }else if(z == z->getParent()->getLeft()){

                z = z->getParent();
                rotateRight(z);

            }

            if(z->getParent() != NULL){

                z->getParent()->color = BLACK;

                if(z->getParent()->getParent() != NULL){    

                    z->getParent()->getParent()->color = RED;
                    rotateLeft(z->getParent()->getParent());

                }
            }

        }

    }

    getRoot()->color = BLACK;
    return true;
}

/* 
 * Search for a node and return true if in tree
 *
 * @param   String      The string encapsulated in node to search for
 * @return  True        if string in the tree
 */
RBTreeNode * RedBlackTree::findNode(string word){
    return static_cast<RBTreeNode *>(BST::findNode(word));
}   

【问题讨论】:

  • @antti:呵呵,我的大学用这个作为作业来淘汰不值得的 CS 学生。但是,不要小看 SO。而且代码的风格还不错,所以+1。
  • 大声笑,冷静 :) 好的,我删除了我之前的评论 :)
  • @antti 太酷了 我只是因为我提出的一些问题而被撕毁,即使我没有其他地方可以寻求帮助。

标签: c++ algorithm data-structures insert red-black-tree


【解决方案1】:

好吧,这可能有点晚了,但我想我对你的问题有一个更简单的解决方案,但如果它是正确的,请随时证明我错了,但这是我对算法描述的解释。

你原来的台词:

}else if(z == z->getParent()->getRight()){
            z = z->getParent();
            rotateLeft(z);

        }

        if(z->getParent() != NULL){

            z->getParent()->color = BLACK;

            if(z->getParent()->getParent() != NULL){

                z->getParent()->getParent()->color = RED;
                rotateRight(z->getParent()->getParent());
            }
        }

我可以替换那些特定行的解决方案,来源:CLRS

逻辑:将 if 块嵌套在 else 中等价于 else if [至少我是这样学习 else if 语句的]

else
{
    if ( z == z->parent->right)
    {
        z = z->parent;
        rotateLeft(z);
    }
    if(z->parent != NULL)
    {
         if(z->parent->parent != NULL)
         {
             z->parent->parent->color = RED;
             rotateRight(z->parent->parent);
         }

    }
}

父母 = getParent() 等等……

对等效的对称情况重复相同的操作。此外,您可以使用前哨节点 nil 来模拟 NULL 指针,但如果您的 Node 类具有构造函数,那么与 NULL 进行比较也可以,除非您找到解决方法。

【讨论】:

    【解决方案2】:

    在插入 165 时已经发生了这种情况。在这种情况下,父级 (160) 和叔叔 (125) 都是红色的。因此,两者都被涂成黑色,它们的父级 (130) 变为红色。

    现在你将它的父级涂成黑色并进行左旋转。但是,此时不应执行此步骤。相反,您必须从头开始递归处理新的红色节点 (130)。

    原因隐藏在 insertFix 的行中,您已将祖父母分配给新节点 z (z = z-&gt;getParent()-&gt;getParent();),但由于缺少 else 分支,仍考虑一个黑色叔叔案例。

    if((y != NULL) && (y->color == RED)){
       ...
    }else if(z == z->getParent()->getRight()){
       ...
    }else if(z->getParent() != NULL){    // <= this else was missing
       ...
    } 
    

    在第二种情况下:

    if((y != NULL) && (y->color == RED)){
        ...
    }else if(z == z->getParent()->getLeft()){
        ...
    }else if(z->getParent() != NULL){    // <= this else also
        ...
    }
    

    【讨论】:

    • 感谢您的帮助。但是,您解决这个问题的过程是什么?两天来我一直在试图解决我的问题,但我无法想出一个很好的解决方案来解决它。您的洞察力会很棒,这样我就不必每次遇到问题时都在论坛上发帖。谢谢!
    • @tpar44 运行程序并在每次插入后打印出树。第一个出错的地方是我插入 165 时。然后我在这个插入调用中运行了一个调试器。检查每一步的动作。我看到您通过将 else 分支与原始算法的描述进行比较来混淆它。
    猜你喜欢
    • 2013-06-12
    • 2012-12-01
    • 2018-11-06
    • 2013-11-17
    • 2011-08-03
    • 2013-05-02
    • 2018-05-30
    • 1970-01-01
    相关资源
    最近更新 更多