數據結構之紅黑樹C源碼實現與剖析

前言 node

    紅黑樹做爲一種經典而高級的數據結構,相信已經被很多人實現過,可是由於程序不夠完善而沒法運行,就是由於程序徹底沒有註釋,初學者根本就看不懂。——這句話相對贊
linux

    此份紅黑樹的C源碼最初從linux-lib-rbtree.c而來,後經一網友那誰(http://www.cppblog.com/converse/)用C寫了出來。在此,向原做者表示敬意。但原來的程序沒有任何一行註釋。沒有一行註釋的程序,令程序的價值大打折扣。
數據結構

    因此,特把這份源代碼在VC6.0上,一行一行的完善,一行一行的給它添加註釋。至此,紅黑樹C帶註釋源碼,就擺在了您的眼前,若有不妥、不正之處,還望不吝指正。
函數


1、紅黑樹C語言源碼實現 測試

目錄:
1、左旋代碼分析
2、右旋
3、紅黑樹查找結點
4、紅黑樹的插入
5、紅黑樹的3種插入狀況
6、紅黑樹的刪除
7、紅黑樹的4種刪除狀況
8、測試用例
spa

//1、左旋代碼分析  
/*----------------------------------------------------------- 
|   node           right 
|   / /    ==>     / / 
|   a  right     node  y 
|       / /       / /     
|       b  y     a   b    //左旋 
-----------------------------------------------------------*/  
static rb_node_t* rb_rotate_left(rb_node_t* node, rb_node_t* root)  
{  
    rb_node_t* right = node->right;    //指定指針指向 right<--node->right  
   
    if ((node->right = right->left))    
    {  
        right->left->parent = node;  //比如上面的註釋圖,node成爲b的父母  
    }  
    right->left = node;   //node成爲right的左孩子  
   
    if ((right->parent = node->parent))  
    {  
        if (node == node->parent->right)  
        {  
            node->parent->right = right;  
        }  
        else  
        {  
            node->parent->left = right;  
        }  
    }  
    else  
    {  
        root = right;  
    }  
    node->parent = right;  //right成爲node的父母  
   
    return root;  
}  
  
  
//2、右旋  
/*----------------------------------------------------------- 
|       node            left 
|       / /             / / 
|    left  y   ==>    a    node 
|   / /                    / / 
|  a   b                  b   y  //右旋與左旋差很少,分析略過 
-----------------------------------------------------------*/  
static rb_node_t* rb_rotate_right(rb_node_t* node, rb_node_t* root)  
{  
    rb_node_t* left = node->left;  
   
    if ((node->left = left->right))  
    {  
        left->right->parent = node;  
    }  
    left->right = node;  
   
    if ((left->parent = node->parent))  
    {  
        if (node == node->parent->right)  
        {  
            node->parent->right = left;  
        }  
        else  
        {  
            node->parent->left = left;  
        }  
    }  
    else  
    {  
        root = left;  
    }  
    node->parent = left;  
   
    return root;  
}  
  
  
//3、紅黑樹查找結點  
//----------------------------------------------------  
//rb_search_auxiliary:查找  
//rb_node_t* rb_search:返回找到的結點  
//----------------------------------------------------  
static rb_node_t* rb_search_auxiliary(key_t key, rb_node_t* root, rb_node_t** save)  
{  
    rb_node_t *node = root, *parent = NULL;  
    int ret;  
   
    while (node)  
    {  
        parent = node;  
        ret = node->key - key;  
        if (0 < ret)  
        {  
            node = node->left;  
        }  
        else if (0 > ret)  
        {  
            node = node->right;  
        }  
        else  
        {  
            return node;  
        }  
    }  
   
    if (save)  
    {  
        *save = parent;  
    }  
   
    return NULL;  
}  
  
//返回上述rb_search_auxiliary查找結果  
rb_node_t* rb_search(key_t key, rb_node_t* root)  
{  
    return rb_search_auxiliary(key, root, NULL);  
}  
  
  
//4、紅黑樹的插入  
//---------------------------------------------------------  
//紅黑樹的插入結點  
rb_node_t* rb_insert(key_t key, data_t data, rb_node_t* root)  
{  
    rb_node_t *parent = NULL, *node;  
   
    parent = NULL;  
    if ((node = rb_search_auxiliary(key, root, &parent)))  //調用rb_search_auxiliary找到插入結  
  
點的地方  
    {  
        return root;  
    }  
   
    node = rb_new_node(key, data);  //分配結點  
    node->parent = parent;     
    node->left = node->right = NULL;  
    node->color = RED;  
   
    if (parent)  
    {  
        if (parent->key > key)  
        {  
            parent->left = node;  
        }  
        else  
        {  
            parent->right = node;  
        }  
    }  
    else  
    {  
        root = node;  
    }  
   
    return rb_insert_rebalance(node, root);   //插入結點後,調用rb_insert_rebalance修復紅黑樹  
  
的性質  
}  
  
  
//5、紅黑樹的3種插入狀況  
//接下來,我們重點分析針對紅黑樹插入的3種狀況,而進行的修復工做。  
//--------------------------------------------------------------  
//紅黑樹修復插入的3種狀況  
//爲了在下面的註釋中表示方便,也爲了讓下述代碼與個人倆篇文章相對應,  
//用z表示當前結點,p[z]表示父母、p[p[z]]表示祖父、y表示叔叔。  
//--------------------------------------------------------------  
static rb_node_t* rb_insert_rebalance(rb_node_t *node, rb_node_t *root)  
{  
    rb_node_t *parent, *gparent, *uncle, *tmp;  //父母p[z]、祖父p[p[z]]、叔叔y、臨時結點*tmp  
   
    while ((parent = node->parent) && parent->color == RED)  
    {     //parent 爲node的父母,且當父母的顏色爲紅時  
        gparent = parent->parent;   //gparent爲祖父  
    
        if (parent == gparent->left)  //當祖父的左孩子即爲父母時。  
                                 //其實上述幾行語句,無非就是理順孩子、父母、祖父的關係。:D。  
        {  
            uncle = gparent->right;  //定義叔叔的概念,叔叔y就是父母的右孩子。  
  
            if (uncle && uncle->color == RED) //狀況1:z的叔叔y是紅色的  
            {  
                uncle->color = BLACK;   //將叔叔結點y着爲黑色  
                parent->color = BLACK;  //z的父母p[z]也着爲黑色。解決z,p[z]都是紅色的問題。  
                gparent->color = RED;    
                node = gparent;     //將祖父當作新增結點z,指針z上移倆層,且着爲紅色。  
            //上述狀況1中,只考慮了z做爲父母的右孩子的狀況。  
            }  
            else                     //狀況2:z的叔叔y是黑色的,  
            {     
                if (parent->right == node)  //且z爲右孩子  
                {  
                    root = rb_rotate_left(parent, root); //左旋[結點z,與父母結點]  
                    tmp = parent;  
                    parent = node;  
                    node = tmp;     //parent與node 互換角色  
                }  
                             //狀況3:z的叔叔y是黑色的,此時z成爲了左孩子。  
                                    //注意,1:狀況3是由上述狀況2變化而來的。  
                                    //......2:z的叔叔老是黑色的,不然就是狀況1了。  
                parent->color = BLACK;   //z的父母p[z]着爲黑色  
                gparent->color = RED;    //原祖父結點着爲紅色  
                root = rb_rotate_right(gparent, root); //右旋[結點z,與祖父結點]  
            }  
        }   
   
        else   
        {       
        // if (parent == gparent->right) 當祖父的右孩子即爲父母時。(解釋請看本文評論下第23樓,同時,感謝SupremeHover指正!)  
            uncle = gparent->left;  //祖父的左孩子做爲叔叔結點。[原理仍是與上部分同樣的]  
            if (uncle && uncle->color == RED)  //狀況1:z的叔叔y是紅色的  
            {  
                uncle->color = BLACK;  
                parent->color = BLACK;  
                gparent->color = RED;  
                node = gparent;           //同上。  
            }  
            else                               //狀況2:z的叔叔y是黑色的,  
            {  
                if (parent->left == node)  //且z爲左孩子  
                {  
                    root = rb_rotate_right(parent, root);  //以結點parent、root右旋  
                    tmp = parent;  
                    parent = node;  
                    node = tmp;       //parent與node 互換角色  
                }   
                  //通過狀況2的變化,成爲了狀況3.  
                parent->color = BLACK;  
                gparent->color = RED;  
                root = rb_rotate_left(gparent, root);   //以結點gparent和root左旋  
            }  
        }  
    }  
   
    root->color = BLACK; //根結點,不論怎樣,都得置爲黑色。  
    return root;      //返回根結點。  
}  
  
  
//6、紅黑樹的刪除  
//------------------------------------------------------------  
//紅黑樹的刪除結點  
rb_node_t* rb_erase(key_t key, rb_node_t *root)  
{  
    rb_node_t *child, *parent, *old, *left, *node;  
    color_t color;  
   
    if (!(node = rb_search_auxiliary(key, root, NULL)))  //調用rb_search_auxiliary查找要刪除的  
  
結點  
    {  
        printf("key %d is not exist!/n");  
        return root;  
    }  
   
    old = node;  
   
    if (node->left && node->right)  
    {  
        node = node->right;  
        while ((left = node->left) != NULL)  
        {  
            node = left;  
        }  
        child = node->right;  
        parent = node->parent;  
        color = node->color;  
    
        if (child)  
        {  
            child->parent = parent;  
        }  
        if (parent)  
        {  
            if (parent->left == node)  
            {  
                parent->left = child;  
            }  
            else  
            {  
                parent->right = child;  
            }  
        }  
        else  
        {  
            root = child;  
        }  
    
        if (node->parent == old)  
        {  
            parent = node;  
        }  
    
        node->parent = old->parent;  
        node->color = old->color;  
        node->right = old->right;  
        node->left = old->left;  
    
        if (old->parent)  
        {  
            if (old->parent->left == old)  
            {  
                old->parent->left = node;  
            }  
            else  
            {  
                old->parent->right = node;  
            }  
        }   
        else  
        {  
            root = node;  
        }  
    
        old->left->parent = node;  
        if (old->right)  
        {  
            old->right->parent = node;  
        }  
    }  
    else  
    {  
        if (!node->left)  
        {  
            child = node->right;  
        }  
        else if (!node->right)  
        {  
            child = node->left;  
        }  
        parent = node->parent;  
        color = node->color;  
    
        if (child)  
        {  
            child->parent = parent;  
        }  
        if (parent)  
        {  
            if (parent->left == node)  
            {  
                parent->left = child;  
            }  
            else  
            {  
                parent->right = child;  
            }  
        }  
        else  
        {  
            root = child;  
        }  
    }  
   
    free(old);  
   
    if (color == BLACK)  
    {  
        root = rb_erase_rebalance(child, parent, root); //調用rb_erase_rebalance來恢復紅黑樹性  
  
質  
    }  
   
    return root;  
}  
  
  
//7、紅黑樹的4種刪除狀況  
//----------------------------------------------------------------  
//紅黑樹修復刪除的4種狀況  
//爲了表示下述註釋的方便,也爲了讓下述代碼與個人倆篇文章相對應,  
//x表示要刪除的結點,*other、w表示兄弟結點,  
//----------------------------------------------------------------  
static rb_node_t* rb_erase_rebalance(rb_node_t *node, rb_node_t *parent, rb_node_t *root)  
{  
    rb_node_t *other, *o_left, *o_right;   //x的兄弟*other,兄弟左孩子*o_left,*o_right  
   
    while ((!node || node->color == BLACK) && node != root)   
    {  
        if (parent->left == node)  
        {  
            other = parent->right;  
            if (other->color == RED)   //狀況1:x的兄弟w是紅色的  
            {  
                other->color = BLACK;    
                parent->color = RED;   //上倆行,改變顏色,w->黑、p[x]->紅。  
                root = rb_rotate_left(parent, root);  //再對p[x]作一次左旋  
                other = parent->right;  //x的新兄弟new w 是旋轉以前w的某個孩子。其實就是左旋後  
  
的效果。  
            }  
            if ((!other->left || other->left->color == BLACK) &&  
                (!other->right || other->right->color == BLACK))    
                          //狀況2:x的兄弟w是黑色,且w的倆個孩子也  
  
都是黑色的  
  
            {                         //因爲w和w的倆個孩子都是黑色的,則在x和w上得去掉一黑色,  
                other->color = RED;   //因而,兄弟w變爲紅色。  
                node = parent;    //p[x]爲新結點x  
                parent = node->parent;  //x<-p[x]  
            }  
            else                       //狀況3:x的兄弟w是黑色的,  
            {                          //且,w的左孩子是紅色,右孩子爲黑色。  
                if (!other->right || other->right->color == BLACK)  
                {  
                    if ((o_left = other->left))   //w和其左孩子left[w],顏色交換。  
                    {  
                        o_left->color = BLACK;    //w的左孩子變爲由黑->紅色  
                    }   
                    other->color = RED;           //w由黑->紅  
                    root = rb_rotate_right(other, root);  //再對w進行右旋,從而紅黑性質恢復。  
                    other = parent->right;        //變化後的,父結點的右孩子,做爲新的兄弟結點  
  
w。  
                }  
                            //狀況4:x的兄弟w是黑色的  
      
                other->color = parent->color;  //把兄弟節點染成當前節點父節點的顏色。  
                parent->color = BLACK;  //把當前節點父節點染成黑色  
                if (other->right)      //且w的右孩子是紅  
                {  
                    other->right->color = BLACK;  //兄弟節點w右孩子染成黑色  
                }  
                root = rb_rotate_left(parent, root);  //並再作一次左旋  
                node = root;   //並把x置爲根。  
                break;  
            }  
        }  
        //下述狀況與上述狀況,原理一致。分析略。  
        else  
        {  
            other = parent->left;  
            if (other->color == RED)  
            {  
                other->color = BLACK;  
                parent->color = RED;  
                root = rb_rotate_right(parent, root);  
                other = parent->left;  
            }  
            if ((!other->left || other->left->color == BLACK) &&  
                (!other->right || other->right->color == BLACK))  
            {  
                other->color = RED;  
                node = parent;  
                parent = node->parent;  
            }  
            else  
            {  
                if (!other->left || other->left->color == BLACK)  
                {  
                    if ((o_right = other->right))  
                    {  
                        o_right->color = BLACK;  
                    }  
                    other->color = RED;  
                    root = rb_rotate_left(other, root);  
                    other = parent->left;  
                }  
                other->color = parent->color;  
                parent->color = BLACK;  
                if (other->left)  
                {  
                    other->left->color = BLACK;  
                }  
                root = rb_rotate_right(parent, root);  
                node = root;  
                break;  
            }  
        }  
    }  
   
    if (node)  
    {  
        node->color = BLACK;  //最後將node[上述步驟置爲了根結點],改成黑色。  
    }    
    return root;  //返回root  
}  
  
  
//8、測試用例  
//主函數  
int main()  
{  
    int i, count = 100;  
    key_t key;  
    rb_node_t* root = NULL, *node = NULL;  
      
    srand(time(NULL));  
    for (i = 1; i < count; ++i)  
    {  
        key = rand() % count;  
        if ((root = rb_insert(key, i, root)))  
        {  
            printf("[i = %d] insert key %d success!/n", i, key);  
        }  
        else  
        {  
            printf("[i = %d] insert key %d error!/n", i, key);  
            exit(-1);  
        }  
    
        if ((node = rb_search(key, root)))  
        {  
            printf("[i = %d] search key %d success!/n", i, key);  
        }  
        else  
        {  
            printf("[i = %d] search key %d error!/n", i, key);  
            exit(-1);  
        }  
        if (!(i % 10))  
        {  
            if ((root = rb_erase(key, root)))  
            {  
                printf("[i = %d] erase key %d success/n", i, key);  
            }  
            else  
            {  
                printf("[i = %d] erase key %d error/n", i, key);  
            }  
        }  
    }  
   
    return 0;  
}
相關文章
相關標籤/搜索