• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            那誰的技術博客

            感興趣領域:高性能服務器編程,存儲,算法,Linux內核
            隨筆 - 210, 文章 - 0, 評論 - 1183, 引用 - 0
            數據加載中……

            [數據結構]紅黑樹的實現源碼

            于2007.11.28:這份代碼是有問題的,修正的在這里:
            http://www.shnenglu.com/converse/archive/2007/11/28/37430.html

            半年之前寫的一個紅黑樹的實現算法了,當時有點忙沒有寫相應的文檔,一下子幾乎全都忘記了,作一個記錄,改天有空了來補充說明文檔.

            /*-----------------------------------------------------------
              RB-Tree的插入和刪除操作的實現算法
              參考資料:
              1) <<Introduction to algorithm>>
              2) <<STL源碼剖析>>
              3) sgi-stl中stl_tree.h中的實現算法
              4) 
            http://epaperpress.com/sortsearch/index.html
              5) 
            http://www.ececs.uc.edu/~franco/C321/html/RedBlack/redblack.html

              作者:李創 (
            http://www.shnenglu.com/converse/)
              您可以自由的傳播,修改這份代碼,轉載處請注明原作者

              紅黑樹的幾個性質:
              1) 每個結點只有紅和黑兩種顏色
              2) 根結點是黑色的
              3) 每個葉子結點(空結點被認為是葉子結點)是黑色的
              4) 如果一個結點是紅色的,那么它的左右兩個子結點的顏色是黑色的
              5) 對于每個結點而言,從這個結點到葉子結點的任何路徑上的黑色結點
              的數目相同
              -------------------------------------------------------------
            */


            #include 
            <stdio.h>
            #include 
            <stdlib.h>
            #include 
            <time.h>

            typedef 
            int KEY;

            enum NODECOLOR
            {
                BLACK        
            = 0,
                RED          
            = 1
            }
            ;

            typedef 
            struct RBTree
            {
                
            struct                RBTree *parent;
                
            struct                RBTree *left, *right;
                KEY                        key;
                NODECOLOR   color;
            }
            RBTree, *PRBTree;

            PRBTree RB_InsertNode(PRBTree root, KEY key);
            PRBTree        RB_InsertNode_Fixup(PRBTree root, PRBTree z);

            PRBTree RB_DeleteNode(PRBTree root, KEY key);
            PRBTree RB_DeleteNode_Fixup(PRBTree root, PRBTree z);

            PRBTree        Find_Node(PRBTree root, KEY key);
            void        Left_Rotate(PRBTree A, PRBTree& root);
            void        Right_Rotate(PRBTree A, PRBTree& root);
            void        Mid_Visit(PRBTree T);
            void        Mid_DeleteTree(PRBTree T);
            void        Print_Node(PRBTree node);

            /*-----------------------------------------------------------
              |   A              B
              |  / \    ==>     / \
              | a   B           A  y
              |    / \         / \
              |    b  y        a  b
              -----------------------------------------------------------
            */

            void Left_Rotate(PRBTree A, PRBTree& root)
            {       
                PRBTree B;
                B 
            = A->right;

                
            if (NULL == B)
                    
            return;

                A
            ->right  = B->left;
                
            if (NULL != B->left)
                    B
            ->left->parent = A;
                B
            ->parent = A->parent;
                
            // 這樣三個判斷連在一起避免了A->parent = NULL的情況
                if (A == root)
                
            {
                    root 
            = B;
                }

                
            else if (A == A->parent->left)
                
            {
                    A
            ->parent->left = B;
                }

                
            else
                
            {
                    A
            ->parent->right = B;
                }

                B
            ->left          = A;
                A
            ->parent = B;
            }


            /*-----------------------------------------------------------
              |    A              B
              |   / \            / \
              |  B   y   ==>    a   A
              | / \                / \
              |a   b              b   y
              -----------------------------------------------------------
            */

            void Right_Rotate(PRBTree A, PRBTree& root)
            {
                PRBTree B;
                B 
            = A->left;

                
            if (NULL == B)
                    
            return;

                A
            ->left   = B->right;
                
            if (NULL != B->right)
                    B
            ->right->parent = A;
                B
            ->parent = A->parent;
                
            // 這樣三個判斷連在一起避免了A->parent = NULL的情況
                if (A == root)
                
            {
                    root 
            = B;
                }

                
            else if (A == A->parent->left)
                
            {
                    A
            ->parent->left = B;
                }

                
            else
                
            {
                    A
            ->parent->right = B;
                }

                A
            ->parent = B;
                B
            ->right  = A;
            }


            /*-----------------------------------------------------------
              |        函數作用:查找key值對應的結點指針
              |        輸入參數:根節點root,待查找關鍵值key
              |        返回參數:如果找到返回結點指針,否則返回NULL
              -------------------------------------------------------------
            */

            PRBTree Find_Node(PRBTree root, KEY key)
            {
                PRBTree x;

                
            // 找到key所在的node
                x = root;
                
            do
                
            {
                    
            if (key == x->key)
                        
            break;
                    
            if (key < x->key)
                    
            {
                        
            if (NULL != x->left)
                            x 
            = x->left;
                        
            else
                            
            break;
                    }

                    
            else
                    
            {
                        
            if (NULL != x->right)
                            x 
            = x->right;
                        
            else
                            
            break;
                    }

                }
             while (NULL != x);

                
            return x;
            }


            /*-----------------------------------------------------------
              |        函數作用:在樹中插入key值
              |        輸入參數:根節點root,待插入結點的關鍵值key
              |        返回參數:根節點root
              -------------------------------------------------------------
            */

            PRBTree RB_InsertNode(PRBTree root, KEY key)
            {
                PRBTree x, y;

                PRBTree z;
                
            if (NULL == (z = (PRBTree)malloc(sizeof(RBTree))))
                
            {
                    printf(
            "Memory alloc error\n");
                    
            return NULL;
                }

                z
            ->key = key;

                
            // 得到z的父節點
                x = root, y = NULL;
                
            while (NULL != x)
                
            {
                    y 
            = x;
                    
            if (z->key < x->key)
                    
            {
                        
            if (NULL != x->left)
                        
            {
                            x 
            = x->left;
                        }

                        
            else
                        
            {
                            
            break;
                        }

                    }

                    
            else
                    
            {
                        
            if (NULL != x->right)
                        
            {
                            x 
            = x->right;
                        }

                        
            else
                        
            {
                            
            break;
                        }

                    }

                }


                
            // 把z放到合適的位置
                z->parent = y;
                
            if (NULL == y)
                
            {
                    root 
            = z;
                }

                
            else
                
            {
                    
            if (z->key < y->key)
                        y
            ->left = z;
                    
            else
                        y
            ->right = z;
                }

                
            // 設置z的左右子樹為空并且顏色是red,注意新插入的節點顏色都是red
                z->left = z->right = NULL;
                z
            ->color = RED;

                
            // 對紅黑樹進行修正
                return RB_InsertNode_Fixup(root, z);
            }


            /*-----------------------------------------------------------
              |        函數作用:對插入key值之后的樹進行修正
              |        輸入參數:根節點root,插入的結點z
              |        返回參數:根節點root
              -------------------------------------------------------------
            */

            PRBTree RB_InsertNode_Fixup(PRBTree root, PRBTree z)
            {
                PRBTree y;
                
            while (root != z && RED == z->parent->color)        // 當z不是根同時父節點的顏色是red
                {
                    
            if (z->parent == z->parent->parent->left)        // 父節點是祖父節點的左子樹
                    {
                        y 
            = z->parent->parent->right;                        // y為z的伯父節點
                        if (NULL != y && RED == y->color)                // 伯父節點存在且顏色是red
                        {
                            z
            ->parent->color = BLACK;                        // 更改z的父節點顏色是B
                            y->color = BLACK;                                        // 更改z的伯父節點顏色是B
                            z->parent->parent->color = RED;                // 更改z的祖父節點顏色是B
                            z = z->parent->parent;                                // 更新z為它的祖父節點
                        }

                        
            else                                                                        // 無伯父節點或者伯父節點顏色是b
                        {
                            
            if (z == z->parent->right)                        // 如果新節點是父節點的右子樹
                            {
                                z 
            = z->parent;
                                Left_Rotate(z, root);
                            }

                            z
            ->parent->color = BLACK;                        // 改變父節點顏色是B
                            z->parent->parent->color = RED;                // 改變祖父節點顏色是R
                            Right_Rotate(z->parent->parent, root);
                        }

                    }

                    
            else                                                                                // 父節點為祖父節點的右子樹
                    {
                        y 
            = z->parent->parent->left;                        // y為z的伯父節點
                        if (NULL != y && RED == y->color)                // 如果y的顏色是red
                        {
                            z
            ->parent->color = BLACK;                        // 更改父節點的顏色為B
                            y->color = BLACK;                                        // 更改伯父節點的顏色是B
                            z->parent->parent->color = RED;                // 更改祖父節點顏色是R
                            z = z->parent->parent;                                // 更改z指向祖父節點
                        }
                           
                        
            else                                                                        // y不存在或者顏色是B
                        {
                            
            if (z == z->parent->left)                        // 如果是父節點的左子樹
                            {
                                z 
            = z->parent;
                                Right_Rotate(z, root);
                            }

                            z
            ->parent->color = BLACK;                        // 改變父節點的顏色是B
                            z->parent->parent->color = RED;                // 改變祖父節點的顏色是RED
                            Left_Rotate(z->parent->parent, root);
                        }

                    }

                }
             // while(RED == z->parent->color)

                
            // 根節點的顏色始終都是B
                root->color = BLACK;

                
            return root;
            }


            /*-----------------------------------------------------------
              |        函數作用:在樹中刪除key值
              |        輸入參數:根節點root,待插入結點的關鍵值key
              |        返回參數:根節點root
              -------------------------------------------------------------
            */

            PRBTree RB_DeleteNode(PRBTree root, KEY key)
            {
                PRBTree x, y, z, x_parent;

                z 
            = Find_Node(root, key);
                
            if (NULL == z)
                    
            return root;

                
            // 當z有一個空子樹的時候,y == z
                
            // 否則,y是大于z最小的結點
                if (NULL == z->left || NULL == z->right)
                    y 
            = z;
                
            else
                
            {
                    y 
            = z->right;
                    
            while (NULL != y->left)
                        y 
            = y->left;
                }


                
            // x是y的子樹,可能為NULL
                if (NULL != y->left)
                    x 
            = y->left;
                
            else
                    x 
            = y->right;

                
            // 設定x的位置取代y
                if (NULL != x)
                    x
            ->parent = y->parent;
                
            if (NULL == y->parent)
                    root 
            = x;
                
            else if (y == y->parent->left)
                    y
            ->parent->left = x;
                
            else
                    y
            ->parent->right = x;

                
            // 把y的key拷貝到z中,這樣y就是待刪除的結點了
                if (y != z)
                
            {
                    z
            ->key = y->key;
                }


                
            // 如果y的顏色值是B,那么要對樹進行修正
                if (BLACK == y->color && NULL != x)
                    RB_DeleteNode_Fixup(root, x);

                free(y);

                
            return root;
            }


            /*-----------------------------------------------------------
              |        函數作用:對刪除key值之后的樹進行修正
              |        輸入參數:根節點root,刪除的結點的子結點x
              |        返回參數:根節點root
              -------------------------------------------------------------
            */

            PRBTree RB_DeleteNode_Fixup(PRBTree root, PRBTree x)
            {
                PRBTree w;

                
            while (x != root && BLACK == x->color)
                
            {
                    
            if (x == x->parent->left)                                                                // 如果x是左子樹
                    {
                        w 
            = x->parent->right;                                                                // w是x的兄弟結點

                        
            if (NULL == w)
                            
            continue;

                        
            if (RED == w->color)                                                                // 如果w的顏色是紅色                                               
                        {
                            w
            ->color = BLACK;
                            x
            ->parent->color = RED;
                            Left_Rotate(x
            ->parent, root);
                            w 
            = x->parent->right;
                        }

                        
            if (NULL != w->left         && BLACK == w->left->color &&
                                NULL 
            != w->right && BLACK == w->right->color)
                        
            {
                            w
            ->color = RED;
                            x 
            = x->parent;
                        }

                        
            else
                        
            {
                            
            if (NULL != w->right && BLACK == w->right->color)
                            
            {
                                w
            ->left->color = BLACK;
                                w
            ->color = RED;
                                Right_Rotate(w, root);
                                w 
            = x->parent->right;
                            }


                            w
            ->color = x->parent->color;
                            x
            ->parent->color = BLACK;
                            w
            ->right->color  = BLACK;
                            Left_Rotate(x
            ->parent, root);
                            x 
            = root;
                        }

                    }

                    
            else
                    
            {
                        w 
            = x->parent->left;
                        
            if (NULL == w)
                            
            continue;
                        
            if (RED == w->color)
                        
            {
                            w
            ->color = BLACK;
                            x
            ->parent->color = RED;
                            Left_Rotate(x
            ->parent, root);
                            w 
            = x->parent->left;
                        }

                        
            if (NULL != w->left         && BLACK == w->left->color &&
                                NULL 
            != w->right && BLACK == w->right->color)
                        
            {
                            w
            ->color = RED;
                            x 
            = x->parent;
                        }

                        
            else
                        
            {
                            
            if (NULL != w->left && BLACK == w->left->color)
                            
            {
                                w
            ->right->color = BLACK;
                                w
            ->color = RED;
                                Left_Rotate(w, root);
                                w 
            = x->parent->left;
                            }


                            w
            ->color = x->parent->color;
                            x
            ->parent->color = BLACK;
                            w
            ->left->color  = BLACK;
                            Right_Rotate(x
            ->parent, root);
                            x 
            = root;
                        }

                    }

                }


                x
            ->color = BLACK;

                
            return root;
            }


            void Print_Node(PRBTree node)
            {
                
            char* color[] = {"BLACK""RED"};
                printf(
            "Key = %d,\tcolor = %s", node->key, color[node->color]);
                
            if (NULL != node->parent)
                    printf(
            ",\tparent = %d", node->parent->key);
                
            if (NULL != node->left)
                    printf(
            ",\tleft = %d", node->left->key);
                
            if (NULL != node->right)
                    printf(
            ",\tright = %d", node->right->key);
                printf(
            "\n");
            }


            // 中序遍歷樹
            void Mid_Visit(PRBTree T)
            {
                
            if (NULL != T)
                
            {
                    
            if (NULL != T->left)
                        Mid_Visit(T
            ->left);
                    Print_Node(T);
                    
            if (NULL != T->right)
                        Mid_Visit(T
            ->right);
                }

            }


            // 中序刪除樹的各個節點
            void Mid_DeleteTree(PRBTree T)
            {
                
            if (NULL != T)
                
            {
                    
            if (NULL != T->left)
                        Mid_DeleteTree(T
            ->left);
                    PRBTree temp 
            = T->right;
                    free(T);
                    T 
            = NULL;
                    
            if (NULL != temp)
                        Mid_DeleteTree(temp);
                }

            }


            void Create_New_Array(int array[], int length)
            {
                
            for (int i = 0; i < length; i++)
                
            {
                    array[i] 
            = rand() % 256;
                }

            }


            int main(int argc, char *argv[])
            {
                
            //int array[10] = {80, 116, 81, 205, 82, 68, 151, 20, 109, 100};
                int array[10];
                srand(time(NULL));
                Create_New_Array(array, 
            10);
                PRBTree root 
            = NULL;
                
            int i;
                
            for (i = 0; i < 10; i++)
                
            {
                    root 
            = RB_InsertNode(root, array[i]);
                }


                Mid_Visit(root);

                
            // 隨機刪除一個結點
                int index = rand() % 10;
                printf(
            "delete node %d\n", array[index]);
                root 
            = RB_DeleteNode(root, array[index]);
                Mid_Visit(root);

                
            // 刪除整顆樹
                Mid_DeleteTree(root);

                
            return 0;
            }

            posted on 2006-10-07 14:32 那誰 閱讀(5666) 評論(12)  編輯 收藏 引用 所屬分類: 算法與數據結構

            評論

            # re: [數據結構]紅黑樹的實現源碼  回復  更多評論   

            PRBTree RB_InsertNode_Fixup(PRBTree root, PRBTree z)
            {
            PRBTree y;
            while (root != z && RED == z->parent->color) // 當z不是根同時父節點的顏色是red
            {
            if (z->parent == z->parent->parent->left) // 父節點是祖父節點的左子樹
            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            {
            y = z->parent->parent->right; // y為z的伯父節點
            if (NULL != y && RED == y->color) // 伯父節點存在且顏色是red
            {
            z->parent->color = BLACK; // 更改z的父節點顏色是B
            y->color = BLACK; // 更改z的伯父節點顏色是B
            z->parent->parent->color = RED; // 更改z的祖父節點顏色是B
            z = z->parent->parent; // 更新z為它的祖父節點
            }
            ================================
            上面代碼中z->parent->parent->left好像會越界!
            請問樓主驗證過自己的實現是完全正確的嗎
            2006-10-15 23:25 | BadNicky

            # re: [數據結構]紅黑樹的實現源碼  回復  更多評論   

            你是對的
            2006-10-18 08:32 | BadNicky

            # re: [數據結構]紅黑樹的實現源碼  回復  更多評論   

            錯了還不改?

            我試了一下,若按算法導論書中,設置葉結點為NIL[T],
            NIL->color=BLACK;
            NIL->key=0;
            // 以下NIL一定要指向本身
            NIL->left=NIL;
            NIL->parent=NIL;
            NIL->right=NIL;
            那么在控制指針越界訪問方面會有很大的優勢!
            2006-10-31 22:47 | pengkuny

            # re: [數據結構]紅黑樹的實現源碼  回復  更多評論   

            錯拉錯拉BadNicky和我都錯拉
            while (z->parent->color == RED)
            {
            if(z->parent == z->parent->parent->left)
            /*既然z的父親p[z]是red,那么p[z]一定不是根結點, p[p[z]]也就一定存在,不會越界.如果你不愿意使用我上面提到的使用NIL,那么你只需要稍微為:*/
            while (NULL != z->parent && z->parent->color == RED)
            那么下面一系列操作都不會越界.
            2006-10-31 23:18 | pengkuny

            # re: [數據結構]紅黑樹的實現源碼  回復  更多評論   

            編譯時出的警告
            PRBTree RB_DeleteNode(PRBTree root, KEY key)
            {
            PRBTree x, y, z, x_parent;
            中 x_parent 沒有定義 怎么解決阿
            2007-04-15 20:49 | miami

            # re: [數據結構]紅黑樹的實現源碼  回復  更多評論   

            這個要贊,最好理解的紅黑樹代碼,注釋很清晰
            2007-06-06 10:57 | j

            # re: [數據結構]紅黑樹的實現源碼  回復  更多評論   

            代碼有Bug.
            你依次插入以下數據:
            int ss[20] = {89, 56 ,457 , 556, 445,
            456, 125, 4571, 741, 7456,
            545, 5662, 475, 1234, 455,
            778, 662, 159, 753, 4565};

            刪除 556,4565 后,剩余的18個節點所構成的RBTree中,再刪除457時出錯。刪除完后 x == NULL ,因此 RB_DeleteNode() 不會調用 RB_DeleteNode_Fixup(),從而返回。而返回后的樹,將會有一路的黑高度為2,其余所有路徑上黑高度為3。不再滿足RBTree條件。
            2007-08-06 11:54 | swxlion

            # re: [數據結構]紅黑樹的實現源碼[未登錄]  回復  更多評論   

            @swxlion

            我測試了一下你說的情況,應該還是平衡的,所有根節點到空結點上的黑顏色結點數目都是3,你可以在調用那三次刪除操作之后調用Mid_Visit函數看看.

            另外,我原來對紅黑樹一個性質的理解是錯誤的:
            3) 每個葉子結點(空結點被認為是葉子結點)是黑色的

            在算法導論中對這條性質的定義是:
            Every leaf (NIL) is black.

            結果我就錯以為是上面描述的那種性質,事實上,在算法導論中,一個空結點也就是上文中的"NIL"才是葉子節點.
            所以對這個性質的定義應該是:
            3)空節點是黑色的(紅黑樹中,根節點的parent以及所有葉節點lchild、rchild都不指向NULL,而是指向一個定義好的空節點)。

            詳見:
            http://lucizm.blog.sohu.com/69218113.html

            另外,這里補充幾個有用的鏈接,包括了紅黑樹和AVL樹的一些比較,分別是:
            http://blog.csdn.net/naivebaby/archive/2006/11/04/1366579.aspx
            http://blog.chinaunix.net/u1/35281/showart_279925.html

            2007-11-04 16:15 | 創系

            # re: [數據結構]紅黑樹的實現源碼  回復  更多評論   

            你的程序有bug.刪除時x==NULL時會出錯。正如swxlion所言
            2007-11-28 13:21 | LL

            # re: [數據結構]紅黑樹的實現源碼  回復  更多評論   

            這份代碼確實是有問題的,修正的放在這里:
            http://www.shnenglu.com/converse/archive/2007/11/28/37430.html
            2007-11-28 14:30 | 創系

            # re: [數據結構]紅黑樹的實現源碼  回復  更多評論   

            http://arreter-masturber-et-castration-chimique.gem-elb.info
            http://video-sexe-hard.vagine-elb.info
            http://zoophile-gay-sexe-video.lexington-elb.info
            http://gratuit-sex-travesti.gem-elb.info
            http://porno-xxx-sexe-cul.lexington-elb.info
            http://rencontre-sexe-live.gem-elb.info
            http://donna-porcella.asiannudes-tun.info
            http://gay-sex-toys.asiannudes-tun.info
            http://photo-de-femme-bite.vagine-elb.info
            http://local-travesti-madrid.es-free-full-porn-video-clip.denrico-elb.info
            http://salon-du-sexe-en-belgique.lexington-elb.info
            http://chichi-xxx-it.teresa-tun.info
            http://wwwvideo-porno-cazzoit.asiannudes-tun.info
            http://salope-brune-bas.gem-elb.info
            http://bionda-sborrata.teresa-tun.info
            http://sexe-lolita-nymphette.lexington-elb.info
            http://cazzone-enorme.asiannudes-tun.info
            http://enculer-tres-soumise.gem-elb.info
            http://annuaire-amaeur-sexe-amatrice-chaude.gem-elb.info
            http://baiser-avec-cam.denrico-elb.info
            http://annonces-salope-telephone-pas-calais.gem-elb.info
            http://etudiante-sexe-sein.vagine-elb.info
            http://video-gratuit-chatte-noire.gem-elb.info
            http://pedo-sexe.gem-elb.info
            http://vip-video-porno-gratis.teresa-tun.info
            2007-12-23 08:07 | dvsvsvdcdsdd

            # re: [數據結構]紅黑樹的實現源碼  回復  更多評論   

            嘿嘿 還是用STL中的RB-TREE放心!
            2008-03-29 21:10 | BaluWu
            99久久亚洲综合精品网站| 国产毛片久久久久久国产毛片| 色成年激情久久综合| 亚洲乱码中文字幕久久孕妇黑人| 亚洲Av无码国产情品久久| 久久精品九九亚洲精品天堂| 久久亚洲精品成人av无码网站| 一个色综合久久| 久久亚洲精品国产亚洲老地址 | 国内精品伊人久久久影院| 国内精品久久久久久久久电影网| 国产福利电影一区二区三区,免费久久久久久久精 | 久久久黄色大片| 无码人妻久久一区二区三区蜜桃| 亚洲人成网站999久久久综合| 亚洲国产成人精品无码久久久久久综合| 国产福利电影一区二区三区久久老子无码午夜伦不 | 日本欧美久久久久免费播放网 | 国产成人无码精品久久久性色| 亚洲中文字幕伊人久久无码| 蜜桃麻豆WWW久久囤产精品| 2021国产精品久久精品| 亚洲va中文字幕无码久久| 久久亚洲AV成人无码电影| 久久99国产精品久久99| 一本大道久久a久久精品综合| 久久精品无码专区免费| 亚洲性久久久影院| 欧美一区二区三区久久综合| 精品亚洲综合久久中文字幕| 丁香久久婷婷国产午夜视频| 亚洲国产日韩欧美久久| 久久综合狠狠综合久久综合88| 97r久久精品国产99国产精| 国产视频久久| 亚洲午夜久久久影院伊人| 97久久国产亚洲精品超碰热| 欧美大战日韩91综合一区婷婷久久青草| 亚洲日韩欧美一区久久久久我| 久久精品人人做人人爽97| 国产精品久久久99|