紅黑樹的實現

在寫完線性容器以後,再來看關聯性容器。在關聯性容器中,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;
}

其運行結果圖如下:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章