红黑树的实现

在写完线性容器以后,再来看关联性容器。在关联性容器中,set,map容器都是基于红黑树而实现的,故花了几天时间写下来红黑树的代码。其原理可以参考算法导论。在写过程中也参照了网上别人写的代码。其代码实现如下:

#include<iostream>
using namespace std;

//红黑树
class RB_Tree
{
private:
    enum COLOR{RED,BLACK};
    class RB_Node
    {
    public:
        RB_Node *left;
        RB_Node *right;
        RB_Node *parent;
        COLOR RB_COLOR;
        int data;
        RB_Node(COLOR _COLOR=BLACK,int _data=0):left(NULL),right(NULL),parent(NULL),data(_data),RB_COLOR(_COLOR){}
    };

private:
    RB_Node *root;   //红黑树的根节点
    RB_Node *nullNode;  //空节点,黑色的

    //插入完成后要记得修复,使其满足红黑树的性质
    //插入时中的三种情况
    void InsertFixUp(RB_Node *node)
    {
        while(node->parent->RB_COLOR==RED)
        {
            //插入节点为父节点的左孩子
            if(node->parent->left==node)
            {
                RB_Node *uncle=node->parent->parent->right;
                if(uncle->RB_COLOR==RED)   //case 1
                {
                    node->parent->RB_COLOR=BLACK;
                    uncle->RB_COLOR=BLACK;
                    node=node->parent->parent;
                    node->RB_COLOR=RED;
                }
                else
                {
                    if(node->parent==node->parent->parent->right)    //case 2
                    {
                        node=node->parent;
                        right_rotate(node);
                       // goto double_left_rotate;
                    }
                    //case2结束以后直接进入case3,或者直接进入case3
                   // double_right_rotate:
                    else{
                        node->parent->RB_COLOR=BLACK;
                        node->parent->parent->RB_COLOR=RED;
                        right_rotate(node->parent->parent);
                    }
                }

            }
            //当节点为为父节点的右孩子
            else
            {
                RB_Node *uncle=node->parent->parent->left;
                if(uncle->RB_COLOR==RED)   //case 1
                {
                    node->parent->RB_COLOR=BLACK;
                    uncle->RB_COLOR=BLACK;
                    node=node->parent->parent;
                    node->RB_COLOR=RED;
                }
                else
                {
                    if(node->parent==node->parent->parent->left)    //case 2
                    {
                        node=node->parent;
                        left_rotate(node);
                       // goto double_right_rotate;
                    }
                    //case2结束以后直接进入case3,或者直接进入case3
                  //  double_left_rotate:
                    else{
                        node->parent->RB_COLOR=BLACK;
                        node->parent->parent->RB_COLOR=RED;
                        left_rotate(node->parent->parent);
                    }
                }
            }
        }
        if(node==root)
            node->RB_COLOR=BLACK;
    }

    //左旋转
    void left_rotate(RB_Node *node)
    {
        RB_Node *temp=node->right;
        temp->parent=node->parent;
        if(node->parent==nullNode)
            root=temp;
        else
        {
            if(node==node->parent->left)
                node->parent->left=temp;
            else
                node->parent->right=temp;
        }
        node->right=temp->left;
        if(temp->left!=nullNode)
            temp->left->parent=node;
        node->parent=temp;
        temp->left=node;
    }
    //右旋转
    void right_rotate(RB_Node *node)
    {
        RB_Node *temp=node->left;
        temp->parent=node->parent;
        if(node==root) //等价于node->parent==NULL
            root=temp;
        else
        {
            if(node==node->parent->left)
                node->parent->left=temp;
            else
                node->parent->right=temp;
        }
        node->left=temp->right;
        if(temp->right!=nullNode)
            temp->right->parent=node;
        node->parent=temp;
        temp->right=node;

    }

    //找到值为value的节点
    RB_Node* find_node(int value)
    {
        RB_Node *temp=root;
        while(temp!=nullNode)
        {
            if(temp->data>value)
                temp=temp->left;
            else if(temp->data<value)
                temp=temp->right;
            else
                break;
        }
        return temp;
    }

    //该函数的功能是用来在删除节点时,如果节点存在左右孩子节点则找到应该替换的节点
    RB_Node* find_delete_node(RB_Node *node)
    {
        if(node->left==nullNode||node==nullNode)
            return nullNode;
        RB_Node *temp=node->left;
        while(temp->right!=nullNode)
            temp=temp->right;
        return temp;

    }


    void deleteFixUp(RB_Node *node)
    {
        RB_Node *temp=node;
        while(temp->RB_COLOR==BLACK&&temp!=root)
        {
            RB_Node *brother;
            //该节点为父节点的左节点
            if(temp==temp->parent->left)
            {
                brother=temp->parent->right;
                if(brother->RB_COLOR==RED)   //case 1
                {
                    temp->parent->RB_COLOR=RED;
                    brother->RB_COLOR=BLACK;
                    //在旋转之后兄弟节点会发生变化,因此在旋转之前就将兄弟节点给换过来
                    brother=brother->left;
                    left_rotate(temp->parent);
                }
                //case 1结束后,会进入case2/case3/case4
                if(brother->left->RB_COLOR==BLACK&&brother->right->RB_COLOR==BLACK)  //case2
                {
                    brother->RB_COLOR=RED;
                    temp=temp->parent;
                }
                else
                {
                    if(brother->right->RB_COLOR==BLACK)   //case 3
                    {
                        brother->RB_COLOR=RED;
                        brother->left->RB_COLOR=BLACK;
                        brother=brother->left;
                        right_rotate(brother->parent);
                    }
                    //进入case4情况
                    brother->RB_COLOR=temp->parent->RB_COLOR;
                    brother->right->RB_COLOR=temp->parent->RB_COLOR=BLACK;
                    left_rotate(temp->parent);
                    temp=root;
                }
            }
            else  //该节点为父节点的右孩子
            {
                brother=temp->parent->left;
                if(brother->RB_COLOR==RED)   //case 1
                {
                    temp->parent->RB_COLOR=RED;
                    brother->RB_COLOR=BLACK;
                    //在旋转之后兄弟节点会发生变化,因此在旋转之前就将兄弟节点给换过来
                    brother=brother->right;
                    right_rotate(temp->parent);
                }
                //case 1结束后,会进入case2/case3/case4
                if(brother->left->RB_COLOR==BLACK&&brother->right->RB_COLOR==BLACK)  //case2
                {
                    brother->RB_COLOR=RED;
                    temp=temp->parent;
                }
                else
                {
                    if(brother->right->RB_COLOR==BLACK)   //case 3
                    {
                        brother->RB_COLOR=RED;
                        brother->left->RB_COLOR=BLACK;
                        brother=brother->left;
                        left_rotate(brother->parent);
                    }
                    //进入case4情况
                    brother->RB_COLOR=temp->parent->RB_COLOR;
                    brother->right->RB_COLOR=temp->parent->RB_COLOR=BLACK;
                    right_rotate(temp->parent);
                    temp=root;
                }

            }
        }
        //最后退出来的时候记得将节点颜色变成黑色
        temp->RB_COLOR=BLACK;
    }
public:
    //构造函数初始化
    RB_Tree()
    {
        nullNode=new RB_Node();
        root=nullNode;
        nullNode->left=nullNode->right=nullNode->parent=nullNode;
    }

    //红黑树的插入操作
    void insert_node(int value)
    {
        RB_Node *node=new RB_Node(RED,value);
        node->left=node->right=node->parent=nullNode;
        if(root==nullNode)    //先把空树的情况处理掉
        {
            root=node;
            root->RB_COLOR=BLACK;
            return ;
        }
        RB_Node *temp=root;
        RB_Node *insert_parent;
        while(temp!=nullNode)
        {
            insert_parent=temp;
            if(temp->data>value)
                temp=temp->left;
            else
                temp=temp->right;
        }
        if(insert_parent->data>value)
            insert_parent->left=node;
        else
            insert_parent->right=node;
        node->parent=insert_parent;
        //完成插入后的修复工作
        InsertFixUp(node);
    }

    //红黑树的删除操作
    void delete_node(int value)
    {
        RB_Node *node=find_node(value);
        RB_Node *delete_node,*delete_node_child;
        if(node->left==nullNode||node->right==nullNode)
            delete_node=node;
        else
            delete_node=find_delete_node(node);

        //如果删除点不是node,则应该将delete_node值复制过来
        if(delete_node!=node)
            node->data=delete_node->data;

        if(delete_node->left!=nullNode)
            delete_node_child=delete_node->left;
        else if(delete_node->right!=nullNode)
            delete_node_child=delete_node->right;
        else
            delete_node_child=nullNode;
        delete_node_child->parent=delete_node->parent;
        if(delete_node==root)
            root=delete_node_child;
        else
        {
            if(delete_node==delete_node->parent->left)
                delete_node->parent->left=delete_node_child;
            else
                delete_node->parent->right=delete_node_child;
        }
        if(delete_node->RB_COLOR==BLACK)
            deleteFixUp(delete_node_child);
        delete delete_node;
    }


    //打印节点
    void display()
    {
        display(root);
    }
    void display(RB_Node *node)
    {
        if(node->left!=nullNode)
            display(node->left);
        if(node!=nullNode)
            cout<<node->data<<" 颜色为:"<<node->RB_COLOR<<endl;
        if(node->right!=nullNode)
            display(node->right);
    }

};

int main()
{
    RB_Tree q;
    int i;
    for(i=1;i<10;i++)
        q.insert_node(i);
    q.display();
    for(i=1;i<10;i++)
    {
         q.delete_node(i);
         cout<<"删除"<<i<<"后:"<<endl;
         q.display();
    }

    return 0;
}

其运行结果图如下:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值