红黑树插入问题

时间:2011-04-15 21:30:08

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

我是新来的红黑树,我遇到麻烦来自这个问题。旋转和插入方法看起来是正确的。但是,当我输入数字时 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)

RedBlackTree.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

RedBlackTree.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));
}   

2 个答案:

答案 0 :(得分:3)

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

现在您将其父黑色绘制成左旋转。但是,此步骤不应该发生。相反,您必须从头开始递归地继续使用新的红色节点(130)。

原因隐藏在insertFix的行中,您已将祖父母分配给新节点zz = z->getParent()->getParent();),但由于遗失,仍然会考虑一个黑人叔叔案例别的分支。

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
    ...
}

答案 1 :(得分:0)

好吧这可能会有点迟到,但我认为我对你的问题有一个更简单的解决方案,但如果它是正确的,可以随意证明我错了,但这是我对算法描述的解释。

您原来的行:

}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

逻辑:嵌套在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);
         }

    }
}

parent = getParent()  等...

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