紅黑樹

黑紅樹

使用的平臺:vs2015

語言:c++

代碼有部分是借鑑的

我是一隻菜鳥,在平衡二叉樹要旋轉的時候總是繞道自己昏頭轉向,自己都弄不懂那棵樹是怎麼旋轉的,其實我也是不太明白了,但是希望我的代碼能夠幫助你們解決問題。代碼有錯誤,提前說啦!!

//核心函數:
//void rb_right_rotate(rbnode* g)
//void rb_left_rotate(rbnode* g)
//void rbt_insert_check(rbnode* node)
//int rbt_insert(rbtree* &tree, keyType key)
//void rbt_delete_check
//int is_black
//int rbt_delete
//左旋和右旋的代碼基本相同,只需要更改right和left
//插入只有4中情況,而刪除有六種
//檢查部分需要細心看

    #include <iostream>

    using namespace std;

    #define COLOR_RED 0  
    #define COLOR_BLACK 1  

    typedef int keyType;

    // 定義而二叉樹節點數據結構  
    struct BinaryTreeNode {
        keyType key;
        int color;
        BinaryTreeNode* parent; // 保存父節點  
        BinaryTreeNode* left; // left child  
        BinaryTreeNode* right; // right child  
        BinaryTreeNode*  next;

    };




    // 定義紅黑樹的結點
    typedef BinaryTreeNode rbnode;

    //  定義紅黑樹
    typedef BinaryTreeNode rbtree;



    //左旋和右旋的代碼基本相同,只需要更改right和left
    //插入只有4中情況,而刪除有六種

    void preorder(rbtree *g);

    void inorder(rbtree *g);

    void postorder(rbtree *g);
    void print(rbtree *g);

    //R
    void rb_right_rotate(rbnode* g) {
        rbnode * p = g->left;   //右轉,p指向g的left

        //交換
        keyType k = g->key;

        g->key = p->key;
        p->key = k;
        //g的左節點是g的做節點的左節點
        g->left = p->left;
        if (NULL != p->left) {//右旋,p的left不能爲空

            p->left->parent = g;
        }
        p->left = p->right;
        p->right = g->right;


        //這個if-else用於將g的父親節點的left或right點指向p,如果g的父節點爲不存在,則樹的parent指向p
        if (NULL != g->right) {
            g->right->parent = p;
        }
        g->right = p;
    }

    // L 
    void rb_left_rotate(rbnode* g) {

        rbnode* p = g->right;
        keyType k = g->key;
        g->key = p->key;
        p->key = k;
        g->right = p->right;
        if (NULL != p->right) {
            p->right->parent = g;
        }
        p->right = p->left;
        p->left = g->left;
        if (NULL != g->left) {
            g->left->parent = p;
        }
        g->left = p;
    }

    // 插入後調整
    void rbt_insert_check(rbnode* node) {
        // CASE 1 :  如果節點等於根節點,則設置節點的顏色爲黑色並返回。
        if (NULL == node->parent) {
            node->color = COLOR_BLACK;
            return;
        }
        // CASE 2 : 當節點的父節點爲黑色時,所有功能都已滿足,停止檢查並返回  
        if (node->parent->color == COLOR_BLACK) {
            return;
        }

        // 父節點爲紅色,這意味着祖父節點存在。 
        rbnode* gf = node->parent->parent;
        rbnode* uf = (gf->left == node->parent) ? gf->right : gf->left;

        // CASE 3 : 當叔叔節點存在並且它是紅時
        if (NULL != uf && uf->color == COLOR_RED) {
            // 設置父親和叔叔黑色,設置祖父紅色
            node->parent->color = COLOR_BLACK;
            uf->color = COLOR_BLACK;
            gf->color = COLOR_RED;
            // 然後重新檢查來自CASE 1的祖父節點處的樹。
            rbt_insert_check(gf);
            return;
        }

        // CASE 4 : 當叔叔是NULL或它的顏色是黑色。
        if (node->parent == gf->left) { // 該節點在其祖父的左邊 
                                        // (a) LL model  
            if (node == node->parent->left) { //該節點在其父節點的左側
                rb_right_rotate(gf);
            }
            // (b) LR model  
            else if (node == node->parent->right) { //該節點在其父節點的右側
                rb_left_rotate(node->parent);
                rb_right_rotate(gf);
            }
        }
        else if (node->parent == gf->right) { //該節點在其祖父節點的右側  
                                              // (c) RR model  
            if (node == node->parent->right) { //該節點在其父節點的右側  
                rb_left_rotate(gf);
            }
            // (d) RL model  
            else if (node == node->parent->left) { //該節點在其父節點的左側 
                rb_right_rotate(node->parent);
                rb_left_rotate(gf);
            }
        }
    }

    // 插入新的關鍵字  
    int rbt_insert(rbtree* &tree, keyType key) {
        if (NULL == tree) { // 樹是否爲空  
            tree = (rbtree*)malloc((sizeof(rbnode)));  //開闢空間
            tree->key = key;
            tree->color = COLOR_BLACK;//根爲黑色
            tree->parent = tree->left = tree->right = NULL;
            return 1;
        }
        //尋找插入點 
        rbnode *n = tree, *p = tree->parent;
        while (NULL != n) {
            if (key == n->key) {  //插入值相同時,不用再插入
                return 0;
            }
            p = n;
            n = (key > p->key) ? p->right : p->left; //排序,有利於插入刪除
        }
        // 插入節點
        n = (rbtree*)malloc((sizeof(rbnode)));
        n->key = key;
        n->color = COLOR_RED; //除了根節點外,插入的節點都是紅色,當調整完後,方可恢復黑色
        n->parent = p;
        n->right = n->left = NULL;
        ((key > p->key) ? p->right : p->left) = n; //判斷插入左節點還是右節點


        // 調整數 
        rbt_insert_check(n);

        return 1;
    }

    int is_black(rbnode * node) {
        if (node == NULL) return 1;
        if (node->color == COLOR_BLACK) return 1;
        return 0;
    }

    //檢查刪除調整後
    void rbt_delete_check(rbnode* p, bool delLeft) {
        rbnode * n = delLeft ? p->left : p->right;
        // case 1: n 是紅
        if (NULL != n && n->color == COLOR_RED) {
            n->color = COLOR_BLACK;
            return;
        }
        // 其他子樹至少一個節點
        rbnode * s = delLeft ? p->right : p->left;
        rbnode * sl = s->left;
        rbnode * sr = s->right;

        // case 2 : S 紅 , p 左轉
        if (s->color == COLOR_RED) {
            if (delLeft) {
                rb_left_rotate(p);
            }
            else {
                rb_right_rotate(p);
            }
            p = s;
            s = delLeft ? sl : sr;
            sl = s->left;
            sr = s->right;
        }
        // Other cases : S 黑  
        // SL 和 SR 黑  
        if (is_black(sl) && is_black(sr)) {
            // case 3 : P紅,  S SL和 SR 黑 
            if (!is_black(p)) {
                p->color = COLOR_BLACK;
                s->color = COLOR_RED;
            }
            // case 4: P ,S, SL,SR 黑
            else {
                s->color = COLOR_RED;
                if (NULL == p->parent) {
                    return;
                }
                delLeft = (p == p->parent->left);
                rbt_delete_check(p->parent, delLeft);
            }
            return;
        }
        // SL 和 SR 有紅色節點  
        if (delLeft) {
            if (is_black(sr)) {    // case 5(a) : delLeft 真 ,SR 黑 
                rb_right_rotate(s);
                sr = s->right;
            }
            rb_left_rotate(p);    // case 6(a) : p節點旋轉
            sr->color = COLOR_BLACK;
        }
        else {
            if (is_black(sl)) {    // case 5(b) : delLeft 假 和SL 黑  
                rb_left_rotate(s);
                sl = s->left;
            }
            rb_right_rotate(p);    // case 6(b) :  p節點旋轉 
            sl->color = COLOR_BLACK;
        }
    }

    // 刪除一個節點 
    int rbt_delete(rbtree* &tree, keyType key) {
        if (NULL == tree) {
            return 0;
        }
        // 尋找節點 
        rbnode *curr, *temp;
        for (curr = tree;;) {
            if (key == curr->key) {
                break;
            }
            curr = (key > curr->key) ? curr->right : curr->left;
            if (NULL == curr) {
                return 0;
            }
        }
        //刪除的有兩個孩子
        if (NULL != curr->left && NULL != curr->right) {
            for (temp = curr->left; NULL != temp->right; temp = temp->right) {
            }
            curr->key = temp->key;
            curr = temp;
        }
        if (NULL == curr->parent) { // 判斷是否樹的根
            tree = (NULL == curr->left) ? curr->right : curr->left;
            if (tree != NULL) {
                tree->color = COLOR_BLACK;
                tree->parent = NULL;
            }
            free(curr);
            return 1;
        }
        // 刪除節點  
        rbnode* fa = curr->parent;
        temp = (NULL == curr->left) ? curr->right : curr->left;
        bool delLeft = (fa->left == curr);
        if (NULL != temp) {
            temp->parent = fa;
        }
        delLeft ? fa->left = temp : fa->right = temp;
        if (curr->color != COLOR_RED) { // adjust after deletion  
            rbt_delete_check(fa, delLeft);
        }
        free(curr);
        return 1;
    }

    void preorder(rbnode *g)
    {
        if (g != NULL)
        {
            cout << g->key<< "  " ;

            preorder(g->left);

            preorder(g->right);



        }


    }

    void inorder(rbnode *g)
    {
        if (g != NULL)
        {
            inorder(g->left);

            cout << g->key<<"  ";

            inorder(g->right);
        }


    }

    void postorder(rbnode *g)
    {
        if (g != NULL)
        {
            postorder(g->left);



            postorder(g->right);

            cout << g->key << "  ";
        }


    }

    void print(rbnode *g)
    {
        //
        cout << "先序輸出 :";

        preorder(g);


        cout << endl;
        cout << "中序輸出 :" ;

        inorder(g);

        cout << endl;
        cout << "後序輸出 :";
        postorder(g);

        cout << endl;

    }

    int main()
    {
        rbnode *p=NULL ;

        cout << "插入數據:\n" << endl;
        for (int i = 0; i <6; i++)
        {
            cout << i + 1 << endl;

            int a;
            cin >> a;
            rbt_insert(p,a);

            print(p);

            cout << endl;

        }


        //cout << "調整後:\n" << endl;
        //print(p);
        //

        cout << "刪除數據 :\n" << endl;
        for (int i = 0; i <5; i++)
        {
            cout << i + 1 << endl;

            int a;
            cin >> a;
            rbt_delete(p, a);

            print(p);

            cout << endl;

        }

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