紅黑樹(二)之 C語言的實現

出自:http://www.cnblogs.com/skywang12345/p/3624177.html

 

概要

紅黑樹在日常的使用中比較常用,例如Java的TreeMapTreeSet,C++的STL,以及Linux內核中都有用到。之前寫過一篇文章專門介紹紅黑樹的理論知識,本文將給出紅黑數的C語言的實現代碼,後序章節再分別給出C++和Java版本的實現。還是那句話,三種實現原理相同,擇其一瞭解即可;若文章有錯誤或不足的地方,望不吝指出!

目錄
1. 紅黑樹的介紹
2. 紅黑樹的C實現(代碼說明)
3. 紅黑樹的C實現(完整源碼)
4. 紅黑樹的C測試程序

轉載請註明出處:http://www.cnblogs.com/skywang12345/p/3624177.html


更多內容數據結構與算法系列 目錄

(01) 紅黑樹(一)之 原理和算法詳細介紹
(02) 紅黑樹(二)之 C語言的實現
(03) 紅黑樹(三)之 Linux內核中紅黑樹的經典實現
(04) 紅黑樹(四)之 C++的實現 
(05) 紅黑樹(五)之 Java的實現
(06) 紅黑樹(六)之 參考資料

 

紅黑樹的介紹

紅黑樹(Red-Black Tree,簡稱R-B Tree),它一種特殊的二叉查找樹。
紅黑樹是特殊的二叉查找樹,意味着它滿足二叉查找樹的特徵:任意一個節點所包含的鍵值,大於等於左孩子的鍵值,小於等於右孩子的鍵值。
除了具備該特性之外,紅黑樹還包括許多額外的信息。

紅黑樹的每個節點上都有存儲位表示節點的顏色,顏色是紅(Red)或黑(Black)。
紅黑樹的特性:
(1) 每個節點或者是黑色,或者是紅色。
(2) 根節點是黑色。
(3) 每個葉子節點是黑色。 [注意:這裏葉子節點,是指爲空的葉子節點!]
(4) 如果一個節點是紅色的,則它的子節點必須是黑色的。
(5) 從一個節點到該節點的子孫節點的所有路徑上包含相同數目的黑節點。

關於它的特性,需要注意的是:
第一,特性(3)中的葉子節點,是隻爲空(NIL或null)的節點。
第二,特性(5),確保沒有一條路徑會比其他路徑長出倆倍。因而,紅黑樹是相對是接近平衡的二叉樹。

紅黑樹示意圖如下:

 

紅黑樹的C實現(代碼說明)

紅黑樹的基本操作是添加刪除旋轉。在對紅黑樹進行添加或刪除後,會用到旋轉方法。爲什麼呢?道理很簡單,添加或刪除紅黑樹中的節點之後,紅黑樹就發生了變化,可能不滿足紅黑樹的5條性質,也就不再是一顆紅黑樹了,而是一顆普通的樹。而通過旋轉,可以使這顆樹重新成爲紅黑樹。簡單點說,旋轉的目的是讓樹保持紅黑樹的特性。
旋轉包括兩種:左旋 和 右旋。下面分別對旋轉(左旋和右旋)、添加、刪除進行介紹。

1. 基本定義

複製代碼
#define RED        0    // 紅色節點
#define BLACK    1    // 黑色節點

typedef int Type;

// 紅黑樹的節點
typedef struct RBTreeNode{
    unsigned char color;        // 顏色(RED 或 BLACK)
    Type   key;                    // 關鍵字(鍵值)
    struct RBTreeNode *left;    // 左孩子
    struct RBTreeNode *right;    // 右孩子
    struct RBTreeNode *parent;    // 父結點
}Node, *RBTree;

// 紅黑樹的根
typedef struct rb_root{
    Node *node;
}RBRoot;
複製代碼

RBTreeNode是紅黑樹的節點類,RBRoot是紅黑樹的根。

 

2. 左旋

對x進行左旋,意味着"將x變成一個左節點"。

左旋的實現代碼(C語言)

複製代碼
/* 
 * 對紅黑樹的節點(x)進行左旋轉
 *
 * 左旋示意圖(對節點x進行左旋):
 *      px                              px
 *     /                               /
 *    x                               y                
 *   /  \      --(左旋)-->           / \                #
 *  lx   y                          x  ry     
 *     /   \                       /  \
 *    ly   ry                     lx  ly  
 *
 *
 */
static void rbtree_left_rotate(RBRoot *root, Node *x)
{
    // 設置x的右孩子爲y
    Node *y = x->right;

    // 將 “y的左孩子” 設爲 “x的右孩子”;
    // 如果y的左孩子非空,將 “x” 設爲 “y的左孩子的父親”
    x->right = y->left;
    if (y->left != NULL)
        y->left->parent = x;

    // 將 “x的父親” 設爲 “y的父親”
    y->parent = x->parent;

    if (x->parent == NULL)
    {
        //tree = y;            // 如果 “x的父親” 是空節點,則將y設爲根節點
        root->node = y;            // 如果 “x的父親” 是空節點,則將y設爲根節點
    }
    else
    {
        if (x->parent->left == x)
            x->parent->left = y;    // 如果 x是它父節點的左孩子,則將y設爲“x的父節點的左孩子”
        else
            x->parent->right = y;    // 如果 x是它父節點的左孩子,則將y設爲“x的父節點的左孩子”
    }
    
    // 將 “x” 設爲 “y的左孩子”
    y->left = x;
    // 將 “x的父節點” 設爲 “y”
    x->parent = y;
}
複製代碼

 

3. 右旋


對y進行左旋,意味着"將y變成一個右節點"。

右旋的實現代碼(C語言)

複製代碼
/* 
 * 對紅黑樹的節點(y)進行右旋轉
 *
 * 右旋示意圖(對節點y進行左旋):
 *            py                               py
 *           /                                /
 *          y                                x                  
 *         /  \      --(右旋)-->            /  \                     #
 *        x   ry                           lx   y  
 *       / \                                   / \                   #
 *      lx  rx                                rx  ry
 * 
 */
static void rbtree_right_rotate(RBRoot *root, Node *y)
{
    // 設置x是當前節點的左孩子。
    Node *x = y->left;

    // 將 “x的右孩子” 設爲 “y的左孩子”;
    // 如果"x的右孩子"不爲空的話,將 “y” 設爲 “x的右孩子的父親”
    y->left = x->right;
    if (x->right != NULL)
        x->right->parent = y;

    // 將 “y的父親” 設爲 “x的父親”
    x->parent = y->parent;

    if (y->parent == NULL) 
    {
        //tree = x;            // 如果 “y的父親” 是空節點,則將x設爲根節點
        root->node = x;            // 如果 “y的父親” 是空節點,則將x設爲根節點
    }
    else
    {
        if (y == y->parent->right)
            y->parent->right = x;    // 如果 y是它父節點的右孩子,則將x設爲“y的父節點的右孩子”
        else
            y->parent->left = x;    // (y是它父節點的左孩子) 將x設爲“x的父節點的左孩子”
    }

    // 將 “y” 設爲 “x的右孩子”
    x->right = y;

    // 將 “y的父節點” 設爲 “x”
    y->parent = x;
}
複製代碼

 

4. 添加

將一個節點(z)插入到紅黑樹中,需要執行哪些步驟呢?首先,將紅黑樹當作一顆二叉查找樹,將節點插入;然後,將節點着色爲紅色;最後,通過"旋轉和重新着色"等一系列操作來修正該樹,使之重新成爲一顆紅黑樹。詳細描述如下:

第一步: 將紅黑樹當作一顆二叉查找樹,將節點插入。
       紅黑樹本身就是一顆二叉查找樹,將節點插入後,該樹仍然是一顆二叉查找樹。也就意味着,樹的鍵值仍然是有序的。此外,無論是左旋還是右旋,若旋轉之前這棵樹是二叉查找樹,旋轉之後它一定還是二叉查找樹。這也就意味着,任何的旋轉和重新着色操作,都不會改變它仍然是一顆二叉查找樹的事實。
       好吧?那接下來,我們就來想方設法的旋轉以及重新着色,使這顆樹重新成爲紅黑樹!

第二步:將插入的節點着色爲"紅色"。
       爲什麼着色成紅色,而不是黑色呢?爲什麼呢?在回答之前,我們需要重新溫習一下紅黑樹的特性:
(1) 每個節點或者是黑色,或者是紅色。
(2) 根節點是黑色。
(3) 每個葉子節點是黑色。 [注意:這裏葉子節點,是指爲空的葉子節點!]
(4) 如果一個節點是紅色的,則它的子節點必須是黑色的。
(5) 從一個節點到該節點的子孫節點的所有路徑上包含相同數目的黑節點。
       將插入的節點着色爲紅色,不會違背"特性(5)"!少違背一條特性,就意味着我們需要處理的情況越少。接下來,就要努力的讓這棵樹滿足其它性質即可;滿足了的話,它就又是一顆紅黑樹了。o(∩∩)o...哈哈

第三步: 通過一系列的旋轉或着色等操作,使之重新成爲一顆紅黑樹。
       第二步中,將插入節點着色爲"紅色"之後,不會違背"特性(5)"。那它到底會違背哪些特性呢?
       對於"特性(1)",顯然不會違背了。因爲我們已經將它塗成紅色了。
       對於"特性(2)",顯然也不會違背。在第一步中,我們是將紅黑樹當作二叉查找樹,然後執行的插入操作。而根據二叉查找數的特點,插入操作不會改變根節點。所以,根節點仍然是黑色。
       對於"特性(3)",顯然不會違背了。這裏的葉子節點是指的空葉子節點,插入非空節點並不會對它們造成影響。
       對於"特性(4)",是有可能違背的!
那接下來,想辦法使之"滿足特性(4)",就可以將樹重新構造成紅黑樹了。


添加操作的實現代碼(C語言)

複製代碼
/*
 * 添加節點:將節點(node)插入到紅黑樹中
 *
 * 參數說明:
 *     root 紅黑樹的根
 *     node 插入的結點        // 對應《算法導論》中的z
 */
static void rbtree_insert(RBRoot *root, Node *node)
{
    Node *y = NULL;
    Node *x = root->node;

    // 1. 將紅黑樹當作一顆二叉查找樹,將節點添加到二叉查找樹中。
    while (x != NULL)
    {
        y = x;
        if (node->key < x->key)
            x = x->left;
        else
            x = x->right;
    }
    rb_parent(node) = y;

    if (y != NULL)
    {
        if (node->key < y->key)
            y->left = node;                // 情況2:若“node所包含的值” < “y所包含的值”,則將node設爲“y的左孩子”
        else
            y->right = node;            // 情況3:(“node所包含的值” >= “y所包含的值”)將node設爲“y的右孩子” 
    }
    else
    {
        root->node = node;                // 情況1:若y是空節點,則將node設爲根
    }

    // 2. 設置節點的顏色爲紅色
    node->color = RED;

    // 3. 將它重新修正爲一顆二叉查找樹
    rbtree_insert_fixup(root, node);
}
複製代碼

rbtree_insert(root, node)的作用是將"node"節點插入到紅黑樹中。其中,root是根,node是被插入節點。
rbtree_insert(root, node)是參考《算法導論》中紅黑樹的插入函數的僞代碼進行實現的。


添加修正操作的實現代碼(C語言)

複製代碼
/*
 * 紅黑樹插入修正函數
 *
 * 在向紅黑樹中插入節點之後(失去平衡),再調用該函數;
 * 目的是將它重新塑造成一顆紅黑樹。
 *
 * 參數說明:
 *     root 紅黑樹的根
 *     node 插入的結點        // 對應《算法導論》中的z
 */
static void rbtree_insert_fixup(RBRoot *root, Node *node)
{
    Node *parent, *gparent;

    // 若“父節點存在,並且父節點的顏色是紅色”
    while ((parent = rb_parent(node)) && rb_is_red(parent))
    {
        gparent = rb_parent(parent);

        //若“父節點”是“祖父節點的左孩子”
        if (parent == gparent->left)
        {
            // Case 1條件:叔叔節點是紅色
            {
                Node *uncle = gparent->right;
                if (uncle && rb_is_red(uncle))
                {
                    rb_set_black(uncle);
                    rb_set_black(parent);
                    rb_set_red(gparent);
                    node = gparent;
                    continue;
                }
            }

            // Case 2條件:叔叔是黑色,且當前節點是右孩子
            if (parent->right == node)
            {
                Node *tmp;
                rbtree_left_rotate(root, parent);
                tmp = parent;
                parent = node;
                node = tmp;
            }

            // Case 3條件:叔叔是黑色,且當前節點是左孩子。
            rb_set_black(parent);
            rb_set_red(gparent);
            rbtree_right_rotate(root, gparent);
        } 
        else//若“z的父節點”是“z的祖父節點的右孩子”
        {
            // Case 1條件:叔叔節點是紅色
            {
                Node *uncle = gparent->left;
                if (uncle && rb_is_red(uncle))
                {
                    rb_set_black(uncle);
                    rb_set_black(parent);
                    rb_set_red(gparent);
                    node = gparent;
                    continue;
                }
            }

            // Case 2條件:叔叔是黑色,且當前節點是左孩子
            if (parent->left == node)
            {
                Node *tmp;
                rbtree_right_rotate(root, parent);
                tmp = parent;
                parent = node;
                node = tmp;
            }

            // Case 3條件:叔叔是黑色,且當前節點是右孩子。
            rb_set_black(parent);
            rb_set_red(gparent);
            rbtree_left_rotate(root, gparent);
        }
    }

    // 將根節點設爲黑色
    rb_set_black(root->node);
}
複製代碼

rbtree_insert_fixup(root, node)的作用是對應"上面所講的第三步"。

 

5. 刪除操作

將紅黑樹內的某一個節點刪除。需要執行的操作依次是:首先,將紅黑樹當作一顆二叉查找樹,將該節點從二叉查找樹中刪除;然後,通過"旋轉和重新着色"等一系列來修正該樹,使之重新成爲一棵紅黑樹。詳細描述如下:

第一步:將紅黑樹當作一顆二叉查找樹,將節點刪除。
       這和"刪除常規二叉查找樹中刪除節點的方法是一樣的"。分3種情況:
① 被刪除節點沒有兒子,即爲葉節點。那麼,直接將該節點刪除就OK了。
② 被刪除節點只有一個兒子。那麼,直接刪除該節點,並用該節點的唯一子節點頂替它的位置。
③ 被刪除節點有兩個兒子。那麼,先找出它的後繼節點;然後把“它的後繼節點的內容”複製給“該節點的內容”;之後,刪除“它的後繼節點”。在這裏,後繼節點相當於替身,在將後繼節點的內容複製給"被刪除節點"之後,再將後繼節點刪除。這樣就巧妙的將問題轉換爲"刪除後繼節點"的情況了,下面就考慮後繼節點。 在"被刪除節點"有兩個非空子節點的情況下,它的後繼節點不可能是雙子非空。既然"的後繼節點"不可能雙子都非空,就意味着"該節點的後繼節點"要麼沒有兒子,要麼只有一個兒子。若沒有兒子,則按"情況① "進行處理;若只有一個兒子,則按"情況② "進行處理。

第二步:通過"旋轉和重新着色"等一系列來修正該樹,使之重新成爲一棵紅黑樹。
因爲"第一步"中刪除節點之後,可能會違背紅黑樹的特性。所以需要通過"旋轉和重新着色"來修正該樹,使之重新成爲一棵紅黑樹。


刪除操作的實現代碼(C語言)

複製代碼
/* 
 * 刪除結點
 *
 * 參數說明:
 *     tree 紅黑樹的根結點
 *     node 刪除的結點
 */
void rbtree_delete(RBRoot *root, Node *node)
{
    Node *child, *parent;
    int color;

    // 被刪除節點的"左右孩子都不爲空"的情況。
    if ( (node->left!=NULL) && (node->right!=NULL) ) 
    {
        // 被刪節點的後繼節點。(稱爲"取代節點")
        // 用它來取代"被刪節點"的位置,然後再將"被刪節點"去掉。
        Node *replace = node;

        // 獲取後繼節點
        replace = replace->right;
        while (replace->left != NULL)
            replace = replace->left;

        // "node節點"不是根節點(只有根節點不存在父節點)
        if (rb_parent(node))
        {
            if (rb_parent(node)->left == node)
                rb_parent(node)->left = replace;
            else
                rb_parent(node)->right = replace;
        } 
        else 
            // "node節點"是根節點,更新根節點。
            root->node = replace;

        // child是"取代節點"的右孩子,也是需要"調整的節點"。
        // "取代節點"肯定不存在左孩子!因爲它是一個後繼節點。
        child = replace->right;
        parent = rb_parent(replace);
        // 保存"取代節點"的顏色
        color = rb_color(replace);

        // "被刪除節點"是"它的後繼節點的父節點"
        if (parent == node)
        {
            parent = replace;
        } 
        else
        {
            // child不爲空
            if (child)
                rb_set_parent(child, parent);
            parent->left = child;

            replace->right = node->right;
            rb_set_parent(node->right, replace);
        }

        replace->parent = node->parent;
        replace->color = node->color;
        replace->left = node->left;
        node->left->parent = replace;

        if (color == BLACK)
            rbtree_delete_fixup(root, child, parent);
        free(node);

        return ;
    }

    if (node->left !=NULL)
        child = node->left;
    else 
        child = node->right;

    parent = node->parent;
    // 保存"取代節點"的顏色
    color = node->color;

    if (child)
        child->parent = parent;

    // "node節點"不是根節點
    if (parent)
    {
        if (parent->left == node)
            parent->left = child;
        else
            parent->right = child;
    }
    else
        root->node = child;

    if (color == BLACK)
        rbtree_delete_fixup(root, child, parent);
    free(node);
}
複製代碼

rbtree_delete(root, node)的作用是將"node"節點插入到紅黑樹中。其中,root是根,node是被插入節點。


刪除修正操作的實現代碼(C語言)

複製代碼
/*
 * 紅黑樹刪除修正函數
 *
 * 在從紅黑樹中刪除插入節點之後(紅黑樹失去平衡),再調用該函數;
 * 目的是將它重新塑造成一顆紅黑樹。
 *
 * 參數說明:
 *     root 紅黑樹的根
 *     node 待修正的節點
 */
static void rbtree_delete_fixup(RBRoot *root, Node *node, Node *parent)
{
    Node *other;

    while ((!node || rb_is_black(node)) && node != root->node)
    {
        if (parent->left == node)
        {
            other = parent->right;
            if (rb_is_red(other))
            {
                // Case 1: x的兄弟w是紅色的  
                rb_set_black(other);
                rb_set_red(parent);
                rbtree_left_rotate(root, parent);
                other = parent->right;
            }
            if ((!other->left || rb_is_black(other->left)) &&
                (!other->right || rb_is_black(other->right)))
            {
                // Case 2: x的兄弟w是黑色,且w的倆個孩子也都是黑色的  
                rb_set_red(other);
                node = parent;
                parent = rb_parent(node);
            }
            else
            {
                if (!other->right || rb_is_black(other->right))
                {
                    // Case 3: x的兄弟w是黑色的,並且w的左孩子是紅色,右孩子爲黑色。  
                    rb_set_black(other->left);
                    rb_set_red(other);
                    rbtree_right_rotate(root, other);
                    other = parent->right;
                }
                // Case 4: x的兄弟w是黑色的;並且w的右孩子是紅色的,左孩子任意顏色。
                rb_set_color(other, rb_color(parent));
                rb_set_black(parent);
                rb_set_black(other->right);
                rbtree_left_rotate(root, parent);
                node = root->node;
                break;
            }
        }
        else
        {
            other = parent->left;
            if (rb_is_red(other))
            {
                // Case 1: x的兄弟w是紅色的  
                rb_set_black(other);
                rb_set_red(parent);
                rbtree_right_rotate(root, parent);
                other = parent->left;
            }
            if ((!other->left || rb_is_black(other->left)) &&
                (!other->right || rb_is_black(other->right)))
            {
                // Case 2: x的兄弟w是黑色,且w的倆個孩子也都是黑色的  
                rb_set_red(other);
                node = parent;
                parent = rb_parent(node);
            }
            else
            {
                if (!other->left || rb_is_black(other->left))
                {
                    // Case 3: x的兄弟w是黑色的,並且w的左孩子是紅色,右孩子爲黑色。  
                    rb_set_black(other->right);
                    rb_set_red(other);
                    rbtree_left_rotate(root, other);
                    other = parent->left;
                }
                // Case 4: x的兄弟w是黑色的;並且w的右孩子是紅色的,左孩子任意顏色。
                rb_set_color(other, rb_color(parent));
                rb_set_black(parent);
                rb_set_black(other->left);
                rbtree_right_rotate(root, parent);
                node = root->node;
                break;
            }
        }
    }
    if (node)
        rb_set_black(node);
}
複製代碼

rbtree_delete_fixup(root, node, parent)是對應"上面所講的第三步"。

 

紅黑樹的C實現(完整源碼)

下面是紅黑數實現的完整代碼和相應的測試程序。
(1) 除了上面所說的"左旋"、"右旋"、"添加"、"刪除"等基本操作之後,還實現了"遍歷"、"查找"、"打印"、"最小值"、"最大值"、"創建"、"銷燬"等接口。
(2) 函數接口分爲內部接口和外部接口。內部接口是static函數,外部接口則是非static函數,外部接口都在.h頭文件中表明瞭。
(3) 測試代碼中提供了"插入"和"刪除"動作的檢測開關。默認是關閉的,打開方法可以參考"代碼中的說明"。建議在打開開關後,在草稿上自己動手繪製一下紅黑樹。

紅黑樹的實現文件(rbtree.h)

複製代碼
 1 #ifndef _RED_BLACK_TREE_H_
 2 #define _RED_BLACK_TREE_H_
 3 
 4 #define RED        0    // 紅色節點
 5 #define BLACK    1    // 黑色節點
 6 
 7 typedef int Type;
 8 
 9 // 紅黑樹的節點
10 typedef struct RBTreeNode{
11     unsigned char color;        // 顏色(RED 或 BLACK)
12     Type   key;                    // 關鍵字(鍵值)
13     struct RBTreeNode *left;    // 左孩子
14     struct RBTreeNode *right;    // 右孩子
15     struct RBTreeNode *parent;    // 父結點
16 }Node, *RBTree;
17 
18 // 紅黑樹的根
19 typedef struct rb_root{
20     Node *node;
21 }RBRoot;
22 
23 // 創建紅黑樹,返回"紅黑樹的根"!
24 RBRoot* create_rbtree();
25 
26 // 銷燬紅黑樹
27 void destroy_rbtree(RBRoot *root);
28 
29 // 將結點插入到紅黑樹中。插入成功,返回0;失敗返回-1。
30 int insert_rbtree(RBRoot *root, Type key);
31 
32 // 刪除結點(key爲節點的值)
33 void delete_rbtree(RBRoot *root, Type key);
34 
35 
36 // 前序遍歷"紅黑樹"
37 void preorder_rbtree(RBRoot *root);
38 // 中序遍歷"紅黑樹"
39 void inorder_rbtree(RBRoot *root);
40 // 後序遍歷"紅黑樹"
41 void postorder_rbtree(RBRoot *root);
42 
43 // (遞歸實現)查找"紅黑樹"中鍵值爲key的節點。找到的話,返回0;否則,返回-1。
44 int rbtree_search(RBRoot *root, Type key);
45 // (非遞歸實現)查找"紅黑樹"中鍵值爲key的節點。找到的話,返回0;否則,返回-1。
46 int iterative_rbtree_search(RBRoot *root, Type key);
47 
48 // 返回最小結點的值(將值保存到val中)。找到的話,返回0;否則返回-1。
49 int rbtree_minimum(RBRoot *root, int *val);
50 // 返回最大結點的值(將值保存到val中)。找到的話,返回0;否則返回-1。
51 int rbtree_maximum(RBRoot *root, int *val);
52 
53 // 打印紅黑樹
54 void print_rbtree(RBRoot *root);
55 
56 #endif
複製代碼

紅黑樹的實現文件(rbtree.c)

複製代碼
  1 /**
  2  * C語言實現的紅黑樹(Red Black Tree)
  3  *
  4  * @author skywang
  5  * @date 2013/11/18
  6  */
  7 
  8 #include <stdio.h>
  9 #include <stdlib.h>
 10 #include "rbtree.h"
 11 
 12 #define rb_parent(r)   ((r)->parent)
 13 #define rb_color(r) ((r)->color)
 14 #define rb_is_red(r)   ((r)->color==RED)
 15 #define rb_is_black(r)  ((r)->color==BLACK)
 16 #define rb_set_black(r)  do { (r)->color = BLACK; } while (0)
 17 #define rb_set_red(r)  do { (r)->color = RED; } while (0)
 18 #define rb_set_parent(r,p)  do { (r)->parent = (p); } while (0)
 19 #define rb_set_color(r,c)  do { (r)->color = (c); } while (0)
 20 
 21 /*
 22  * 創建紅黑樹,返回"紅黑樹的根"!
 23  */
 24 RBRoot* create_rbtree()
 25 {
 26     RBRoot *root = (RBRoot *)malloc(sizeof(RBRoot));
 27     root->node = NULL;
 28 
 29     return root;
 30 }
 31 
 32 /*
 33  * 前序遍歷"紅黑樹"
 34  */
 35 static void preorder(RBTree tree)
 36 {
 37     if(tree != NULL)
 38     {
 39         printf("%d ", tree->key);
 40         preorder(tree->left);
 41         preorder(tree->right);
 42     }
 43 }
 44 void preorder_rbtree(RBRoot *root) 
 45 {
 46     if (root)
 47         preorder(root->node);
 48 }
 49 
 50 /*
 51  * 中序遍歷"紅黑樹"
 52  */
 53 static void inorder(RBTree tree)
 54 {
 55     if(tree != NULL)
 56     {
 57         inorder(tree->left);
 58         printf("%d ", tree->key);
 59         inorder(tree->right);
 60     }
 61 }
 62 
 63 void inorder_rbtree(RBRoot *root) 
 64 {
 65     if (root)
 66         inorder(root->node);
 67 }
 68 
 69 /*
 70  * 後序遍歷"紅黑樹"
 71  */
 72 static void postorder(RBTree tree)
 73 {
 74     if(tree != NULL)
 75     {
 76         postorder(tree->left);
 77         postorder(tree->right);
 78         printf("%d ", tree->key);
 79     }
 80 }
 81 
 82 void postorder_rbtree(RBRoot *root)
 83 {
 84     if (root)
 85         postorder(root->node);
 86 }
 87 
 88 /*
 89  * (遞歸實現)查找"紅黑樹x"中鍵值爲key的節點
 90  */
 91 static Node* search(RBTree x, Type key)
 92 {
 93     if (x==NULL || x->key==key)
 94         return x;
 95 
 96     if (key < x->key)
 97         return search(x->left, key);
 98     else
 99         return search(x->right, key);
100 }
101 int rbtree_search(RBRoot *root, Type key)
102 {
103     if (root)
104         return search(root->node, key)? 0 : -1;
105 }
106 
107 /*
108  * (非遞歸實現)查找"紅黑樹x"中鍵值爲key的節點
109  */
110 static Node* iterative_search(RBTree x, Type key)
111 {
112     while ((x!=NULL) && (x->key!=key))
113     {
114         if (key < x->key)
115             x = x->left;
116         else
117             x = x->right;
118     }
119 
120     return x;
121 }
122 int iterative_rbtree_search(RBRoot *root, Type key)
123 {
124     if (root)
125         return iterative_search(root->node, key) ? 0 : -1;
126 }
127 
128 /* 
129  * 查找最小結點:返回tree爲根結點的紅黑樹的最小結點。
130  */
131 static Node* minimum(RBTree tree)
132 {
133     if (tree == NULL)
134         return NULL;
135 
136     while(tree->left != NULL)
137         tree = tree->left;
138     return tree;
139 }
140 
141 int rbtree_minimum(RBRoot *root, int *val)
142 {
143     Node *node;
144 
145     if (root)
146         node = minimum(root->node);
147 
148     if (node == NULL)
149         return -1;
150 
151     *val = node->key;
152     return 0;
153 }
154  
155 /* 
156  * 查找最大結點:返回tree爲根結點的紅黑樹的最大結點。
157  */
158 static Node* maximum(RBTree tree)
159 {
160     if (tree == NULL)
161         return NULL;
162 
163     while(tree->right != NULL)
164         tree = tree->right;
165     return tree;
166 }
167 
168 int rbtree_maximum(RBRoot *root, int *val)
169 {
170     Node *node;
171 
172     if (root)
173         node = maximum(root->node);
174 
175     if (node == NULL)
176         return -1;
177 
178     *val = node->key;
179     return 0;
180 }
181 
182 /* 
183  * 找結點(x)的後繼結點。即,查找"紅黑樹中數據值大於該結點"的"最小結點"。
184  */
185 static Node* rbtree_successor(RBTree x)
186 {
187     // 如果x存在右孩子,則"x的後繼結點"爲 "以其右孩子爲根的子樹的最小結點"。
188     if (x->right != NULL)
189         return minimum(x->right);
190 
191     // 如果x沒有右孩子。則x有以下兩種可能:
192     // (01) x是"一個左孩子",則"x的後繼結點"爲 "它的父結點"。
193     // (02) x是"一個右孩子",則查找"x的最低的父結點,並且該父結點要具有左孩子",找到的這個"最低的父結點"就是"x的後繼結點"。
194     Node* y = x->parent;
195     while ((y!=NULL) && (x==y->right))
196     {
197         x = y;
198         y = y->parent;
199     }
200 
201     return y;
202 }
203  
204 /* 
205  * 找結點(x)的前驅結點。即,查找"紅黑樹中數據值小於該結點"的"最大結點"。
206  */
207 static Node* rbtree_predecessor(RBTree x)
208 {
209     // 如果x存在左孩子,則"x的前驅結點"爲 "以其左孩子爲根的子樹的最大結點"。
210     if (x->left != NULL)
211         return maximum(x->left);
212 
213     // 如果x沒有左孩子。則x有以下兩種可能:
214     // (01) x是"一個右孩子",則"x的前驅結點"爲 "它的父結點"。
215     // (01) x是"一個左孩子",則查找"x的最低的父結點,並且該父結點要具有右孩子",找到的這個"最低的父結點"就是"x的前驅結點"。
216     Node* y = x->parent;
217     while ((y!=NULL) && (x==y->left))
218     {
219         x = y;
220         y = y->parent;
221     }
222 
223     return y;
224 }
225 
226 /* 
227  * 對紅黑樹的節點(x)進行左旋轉
228  *
229  * 左旋示意圖(對節點x進行左旋):
230  *      px                              px
231  *     /                               /
232  *    x                               y                
233  *   /  \      --(左旋)-->           / \                #
234  *  lx   y                          x  ry     
235  *     /   \                       /  \
236  *    ly   ry                     lx  ly  
237  *
238  *
239  */
240 static void rbtree_left_rotate(RBRoot *root, Node *x)
241 {
242     // 設置x的右孩子爲y
243     Node *y = x->right;
244 
245     // 將 “y的左孩子” 設爲 “x的右孩子”;
246     // 如果y的左孩子非空,將 “x” 設爲 “y的左孩子的父親”
247     x->right = y->left;
248     if (y->left != NULL)
249         y->left->parent = x;
250 
251     // 將 “x的父親” 設爲 “y的父親”
252     y->parent = x->parent;
253 
254     if (x->parent == NULL)
255     {
256         //tree = y;            // 如果 “x的父親” 是空節點,則將y設爲根節點
257         root->node = y;            // 如果 “x的父親” 是空節點,則將y設爲根節點
258     }
259     else
260     {
261         if (x->parent->left == x)
262             x->parent->left = y;    // 如果 x是它父節點的左孩子,則將y設爲“x的父節點的左孩子”
263         else
264             x->parent->right = y;    // 如果 x是它父節點的左孩子,則將y設爲“x的父節點的左孩子”
265     }
266     
267     // 將 “x” 設爲 “y的左孩子”
268     y->left = x;
269     // 將 “x的父節點” 設爲 “y”
270     x->parent = y;
271 }
272 
273 /* 
274  * 對紅黑樹的節點(y)進行右旋轉
275  *
276  * 右旋示意圖(對節點y進行左旋):
277  *            py                               py
278  *           /                                /
279  *          y                                x                  
280  *         /  \      --(右旋)-->            /  \                     #
281  *        x   ry                           lx   y  
282  *       / \                                   / \                   #
283  *      lx  rx                                rx  ry
284  * 
285  */
286 static void rbtree_right_rotate(RBRoot *root, Node *y)
287 {
288     // 設置x是當前節點的左孩子。
289     Node *x = y->left;
290 
291     // 將 “x的右孩子” 設爲 “y的左孩子”;
292     // 如果"x的右孩子"不爲空的話,將 “y” 設爲 “x的右孩子的父親”
293     y->left = x->right;
294     if (x->right != NULL)
295         x->right->parent = y;
296 
297     // 將 “y的父親” 設爲 “x的父親”
298     x->parent = y->parent;
299 
300     if (y->parent == NULL) 
301     {
302         //tree = x;            // 如果 “y的父親” 是空節點,則將x設爲根節點
303         root->node = x;            // 如果 “y的父親” 是空節點,則將x設爲根節點
304     }
305     else
306     {
307         if (y == y->parent->right)
308             y->parent->right = x;    // 如果 y是它父節點的右孩子,則將x設爲“y的父節點的右孩子”
309         else
310             y->parent->left = x;    // (y是它父節點的左孩子) 將x設爲“x的父節點的左孩子”
311     }
312 
313     // 將 “y” 設爲 “x的右孩子”
314     x->right = y;
315 
316     // 將 “y的父節點” 設爲 “x”
317     y->parent = x;
318 }
319 
320 /*
321  * 紅黑樹插入修正函數
322  *
323  * 在向紅黑樹中插入節點之後(失去平衡),再調用該函數;
324  * 目的是將它重新塑造成一顆紅黑樹。
325  *
326  * 參數說明:
327  *     root 紅黑樹的根
328  *     node 插入的結點        // 對應《算法導論》中的z
329  */
330 static void rbtree_insert_fixup(RBRoot *root, Node *node)
331 {
332     Node *parent, *gparent;
333 
334     // 若“父節點存在,並且父節點的顏色是紅色”
335     while ((parent = rb_parent(node)) && rb_is_red(parent))
336     {
337         gparent = rb_parent(parent);
338 
339         //若“父節點”是“祖父節點的左孩子”
340         if (parent == gparent->left)
341         {
342             // Case 1條件:叔叔節點是紅色
343             {
344                 Node *uncle = gparent->right;
345                 if (uncle && rb_is_red(uncle))
346                 {
347                     rb_set_black(uncle);
348                     rb_set_black(parent);
349                     rb_set_red(gparent);
350                     node = gparent;
351                     continue;
352                 }
353             }
354 
355             // Case 2條件:叔叔是黑色,且當前節點是右孩子
356             if (parent->right == node)
357             {
358                 Node *tmp;
359                 rbtree_left_rotate(root, parent);
360                 tmp = parent;
361                 parent = node;
362                 node = tmp;
363             }
364 
365             // Case 3條件:叔叔是黑色,且當前節點是左孩子。
366             rb_set_black(parent);
367             rb_set_red(gparent);
368             rbtree_right_rotate(root, gparent);
369         } 
370         else//若“z的父節點”是“z的祖父節點的右孩子”
371         {
372             // Case 1條件:叔叔節點是紅色
373             {
374                 Node *uncle = gparent->left;
375                 if (uncle && rb_is_red(uncle))
376                 {
377                     rb_set_black(uncle);
378                     rb_set_black(parent);
379                     rb_set_red(gparent);
380                     node = gparent;
381                     continue;
382                 }
383             }
384 
385             // Case 2條件:叔叔是黑色,且當前節點是左孩子
386             if (parent->left == node)
387             {
388                 Node *tmp;
389                 rbtree_right_rotate(root, parent);
390                 tmp = parent;
391                 parent = node;
392                 node = tmp;
393             }
394 
395             // Case 3條件:叔叔是黑色,且當前節點是右孩子。
396             rb_set_black(parent);
397             rb_set_red(gparent);
398             rbtree_left_rotate(root, gparent);
399         }
400     }
401 
402     // 將根節點設爲黑色
403     rb_set_black(root->node);
404 }
405 
406 /*
407  * 添加節點:將節點(node)插入到紅黑樹中
408  *
409  * 參數說明:
410  *     root 紅黑樹的根
411  *     node 插入的結點        // 對應《算法導論》中的z
412  */
413 static void rbtree_insert(RBRoot *root, Node *node)
414 {
415     Node *y = NULL;
416     Node *x = root->node;
417 
418     // 1. 將紅黑樹當作一顆二叉查找樹,將節點添加到二叉查找樹中。
419     while (x != NULL)
420     {
421         y = x;
422         if (node->key < x->key)
423             x = x->left;
424         else
425             x = x->right;
426     }
427     rb_parent(node) = y;
428 
429     if (y != NULL)
430     {
431         if (node->key < y->key)
432             y->left = node;                // 情況2:若“node所包含的值” < “y所包含的值”,則將node設爲“y的左孩子”
433         else
434             y->right = node;            // 情況3:(“node所包含的值” >= “y所包含的值”)將node設爲“y的右孩子” 
435     }
436     else
437     {
438         root->node = node;                // 情況1:若y是空節點,則將node設爲根
439     }
440 
441     // 2. 設置節點的顏色爲紅色
442     node->color = RED;
443 
444     // 3. 將它重新修正爲一顆二叉查找樹
445     rbtree_insert_fixup(root, node);
446 }
447 
448 /*
449  * 創建結點
450  *
451  * 參數說明:
452  *     key 是鍵值。
453  *     parent 是父結點。
454  *     left 是左孩子。
455  *     right 是右孩子。
456  */
457 static Node* create_rbtree_node(Type key, Node *parent, Node *left, Node* right)
458 {
459     Node* p;
460 
461     if ((p = (Node *)malloc(sizeof(Node))) == NULL)
462         return NULL;
463     p->key = key;
464     p->left = left;
465     p->right = right;
466     p->parent = parent;
467     p->color = BLACK; // 默認爲黑色
468 
469     return p;
470 }
471 
472 /* 
473  * 新建結點(節點鍵值爲key),並將其插入到紅黑樹中
474  *
475  * 參數說明:
476  *     root 紅黑樹的根
477  *     key 插入結點的鍵值
478  * 返回值:
479  *     0,插入成功
480  *     -1,插入失敗
481  */
482 int insert_rbtree(RBRoot *root, Type key)
483 {
484     Node *node;    // 新建結點
485 
486     // 不允許插入相同鍵值的節點。
487     // (若想允許插入相同鍵值的節點,註釋掉下面兩句話即可!)
488     if (search(root->node, key) != NULL)
489         return -1;
490 
491     // 如果新建結點失敗,則返回。
492     if ((node=create_rbtree_node(key, NULL, NULL, NULL)) == NULL)
493         return -1;
494 
495     rbtree_insert(root, node);
496 
497     return 0;
498 }
499 
500 /*
501  * 紅黑樹刪除修正函數
502  *
503  * 在從紅黑樹中刪除插入節點之後(紅黑樹失去平衡),再調用該函數;
504  * 目的是將它重新塑造成一顆紅黑樹。
505  *
506  * 參數說明:
507  *     root 紅黑樹的根
508  *     node 待修正的節點
509  */
510 static void rbtree_delete_fixup(RBRoot *root, Node *node, Node *parent)
511 {
512     Node *other;
513 
514     while ((!node || rb_is_black(node)) && node != root->node)
515     {
516         if (parent->left == node)
517         {
518             other = parent->right;
519             if (rb_is_red(other))
520             {
521                 // Case 1: x的兄弟w是紅色的  
522                 rb_set_black(other);
523                 rb_set_red(parent);
524                 rbtree_left_rotate(root, parent);
525                 other = parent->right;
526             }
527             if ((!other->left || rb_is_black(other->left)) &&
528                 (!other->right || rb_is_black(other->right)))
529             {
530                 // Case 2: x的兄弟w是黑色,且w的倆個孩子也都是黑色的  
531                 rb_set_red(other);
532                 node = parent;
533                 parent = rb_parent(node);
534             }
535             else
536             {
537                 if (!other->right || rb_is_black(other->right))
538                 {
539                     // Case 3: x的兄弟w是黑色的,並且w的左孩子是紅色,右孩子爲黑色。  
540                     rb_set_black(other->left);
541                     rb_set_red(other);
542                     rbtree_right_rotate(root, other);
543                     other = parent->right;
544                 }
545                 // Case 4: x的兄弟w是黑色的;並且w的右孩子是紅色的,左孩子任意顏色。
546                 rb_set_color(other, rb_color(parent));
547                 rb_set_black(parent);
548                 rb_set_black(other->right);
549                 rbtree_left_rotate(root, parent);
550                 node = root->node;
551                 break;
552             }
553         }
554         else
555         {
556             other = parent->left;
557             if (rb_is_red(other))
558             {
559                 // Case 1: x的兄弟w是紅色的  
560                 rb_set_black(other);
561                 rb_set_red(parent);
562                 rbtree_right_rotate(root, parent);
563                 other = parent->left;
564             }
565             if ((!other->left || rb_is_black(other->left)) &&
566                 (!other->right || rb_is_black(other->right)))
567             {
568                 // Case 2: x的兄弟w是黑色,且w的倆個孩子也都是黑色的  
569                 rb_set_red(other);
570                 node = parent;
571                 parent = rb_parent(node);
572             }
573             else
574             {
575                 if (!other->left || rb_is_black(other->left))
576                 {
577                     // Case 3: x的兄弟w是黑色的,並且w的左孩子是紅色,右孩子爲黑色。  
578                     rb_set_black(other->right);
579                     rb_set_red(other);
580                     rbtree_left_rotate(root, other);
581                     other = parent->left;
582                 }
583                 // Case 4: x的兄弟w是黑色的;並且w的右孩子是紅色的,左孩子任意顏色。
584                 rb_set_color(other, rb_color(parent));
585                 rb_set_black(parent);
586                 rb_set_black(other->left);
587                 rbtree_right_rotate(root, parent);
588                 node = root->node;
589                 break;
590             }
591         }
592     }
593     if (node)
594         rb_set_black(node);
595 }
596 
597 /* 
598  * 刪除結點
599  *
600  * 參數說明:
601  *     tree 紅黑樹的根結點
602  *     node 刪除的結點
603  */
604 void rbtree_delete(RBRoot *root, Node *node)
605 {
606     Node *child, *parent;
607     int color;
608 
609     // 被刪除節點的"左右孩子都不爲空"的情況。
610     if ( (node->left!=NULL) && (node->right!=NULL) ) 
611     {
612         // 被刪節點的後繼節點。(稱爲"取代節點")
613         // 用它來取代"被刪節點"的位置,然後再將"被刪節點"去掉。
614         Node *replace = node;
615 
616         // 獲取後繼節點
617         replace = replace->right;
618         while (replace->left != NULL)
619             replace = replace->left;
620 
621         // "node節點"不是根節點(只有根節點不存在父節點)
622         if (rb_parent(node))
623         {
624             if (rb_parent(node)->left == node)
625                 rb_parent(node)->left = replace;
626             else
627                 rb_parent(node)->right = replace;
628         } 
629         else 
630             // "node節點"是根節點,更新根節點。
631             root->node = replace;
632 
633         // child是"取代節點"的右孩子,也是需要"調整的節點"。
634         // "取代節點"肯定不存在左孩子!因爲它是一個後繼節點。
635         child = replace->right;
636         parent = rb_parent(replace);
637         // 保存"取代節點"的顏色
638         color = rb_color(replace);
639 
640         // "被刪除節點"是"它的後繼節點的父節點"
641         if (parent == node)
642         {
643             parent = replace;
644         } 
645         else
646         {
647             // child不爲空
648             if (child)
649                 rb_set_parent(child, parent);
650             parent->left = child;
651 
652             replace->right = node->right;
653             rb_set_parent(node->right, replace);
654         }
655 
656         replace->parent = node->parent;
657         replace->color = node->color;
658         replace->left = node->left;
659         node->left->parent = replace;
660 
661         if (color == BLACK)
662             rbtree_delete_fixup(root, child, parent);
663         free(node);
664 
665         return ;
666     }
667 
668     if (node->left !=NULL)
669         child = node->left;
670     else 
671         child = node->right;
672 
673     parent = node->parent;
674     // 保存"取代節點"的顏色
675     color = node->color;
676 
677     if (child)
678         child->parent = parent;
679 
680     // "node節點"不是根節點
681     if (parent)
682     {
683         if (parent->left == node)
684             parent->left = child;
685         else
686             parent->right = child;
687     }
688     else
689         root->node = child;
690 
691     if (color == BLACK)
692         rbtree_delete_fixup(root, child, parent);
693     free(node);
694 }
695 
696 /* 
697  * 刪除鍵值爲key的結點
698  *
699  * 參數說明:
700  *     tree 紅黑樹的根結點
701  *     key 鍵值
702  */
703 void delete_rbtree(RBRoot *root, Type key)
704 {
705     Node *z, *node; 
706 
707     if ((z = search(root->node, key)) != NULL)
708         rbtree_delete(root, z);
709 }
710 
711 /*
712  * 銷燬紅黑樹
713  */
714 static void rbtree_destroy(RBTree tree)
715 {
716     if (tree==NULL)
717         return ;
718 
719     if (tree->left != NULL)
720         rbtree_destroy(tree->left);
721     if (tree->right != NULL)
722         rbtree_destroy(tree->right);
723 
724     free(tree);
725 }
726 
727 void destroy_rbtree(RBRoot *root)
728 {
729     if (root != NULL)
730         rbtree_destroy(root->node);
731 
732     free(root);
733 }
734 
735 /*
736  * 打印"紅黑樹"
737  *
738  * tree       -- 紅黑樹的節點
739  * key        -- 節點的鍵值 
740  * direction  --  0,表示該節點是根節點;
741  *               -1,表示該節點是它的父結點的左孩子;
742  *                1,表示該節點是它的父結點的右孩子。
743  */
744 static void rbtree_print(RBTree tree, Type key, int direction)
745 {
746     if(tree != NULL)
747     {
748         if(direction==0)    // tree是根節點
749             printf("%2d(B) is root\n", tree->key);
750         else                // tree是分支節點
751             printf("%2d(%s) is %2d's %6s child\n", tree->key, rb_is_red(tree)?"R":"B", key, direction==1?"right" : "left");
752 
753         rbtree_print(tree->left, tree->key, -1);
754         rbtree_print(tree->right,tree->key,  1);
755     }
756 }
757 
758 void print_rbtree(RBRoot *root)
759 {
760     if (root!=NULL && root->node!=NULL)
761         rbtree_print(root->node, root->node->key, 0);
762 }
複製代碼

紅黑樹的測試文件(rbtree_test.c)

複製代碼
 1 /**
 2  * C語言實現的紅黑樹(Red Black Tree)
 3  *
 4  * @author skywang
 5  * @date 2013/11/18
 6  */
 7 
 8 #include <stdio.h>
 9 #include "rbtree.h"
10 
11 #define CHECK_INSERT 0    // "插入"動作的檢測開關(0,關閉;1,打開)
12 #define CHECK_DELETE 0    // "刪除"動作的檢測開關(0,關閉;1,打開)
13 #define LENGTH(a) ( (sizeof(a)) / (sizeof(a[0])) )
14 
15 void main()
16 {
17     int a[] = {10, 40, 30, 60, 90, 70, 20, 50, 80};
18     int i, ilen=LENGTH(a);
19     RBRoot *root=NULL;
20 
21     root = create_rbtree();
22     printf("== 原始數據: ");
23     for(i=0; i<ilen; i++)
24         printf("%d ", a[i]);
25     printf("\n");
26 
27     for(i=0; i<ilen; i++)
28     {
29         insert_rbtree(root, a[i]);
30 #if CHECK_INSERT
31         printf("== 添加節點: %d\n", a[i]);
32         printf("== 樹的詳細信息: \n");
33         print_rbtree(root);
34         printf("\n");
35 #endif
36     }
37 
38     printf("== 前序遍歷: ");
39     preorder_rbtree(root);
40 
41     printf("\n== 中序遍歷: ");
42     inorder_rbtree(root);
43 
44     printf("\n== 後序遍歷: ");
45     postorder_rbtree(root);
46     printf("\n");
47 
48     if (rbtree_minimum(root, &i)==0)
49         printf("== 最小值: %d\n", i);
50     if (rbtree_maximum(root, &i)==0)
51         printf("== 最大值: %d\n", i);
52     printf("== 樹的詳細信息: \n");
53     print_rbtree(root);
54     printf("\n");
55 
56 #if CHECK_DELETE
57     for(i=0; i<ilen; i++)
58     {
59         delete_rbtree(root, a[i]);
60 
61         printf("== 刪除節點: %d\n", a[i]);
62         if (root)
63         {
64             printf("== 樹的詳細信息: \n");
65             print_rbtree(root);
66             printf("\n");
67         }
68     }
69 #endif
70 
71     destroy_rbtree(root);
72 }
複製代碼

 

紅黑樹的C測試程序

前面已經給出了紅黑樹的測試程序(rbtree_test.c),這裏就不再重複說明。下面是測試程序的運行結果:

複製代碼
== 原始數據: 10 40 30 60 90 70 20 50 80 
== 前序遍歷: 30 10 20 60 40 50 80 70 90 
== 中序遍歷: 10 20 30 40 50 60 70 80 90 
== 後序遍歷: 20 10 50 40 70 90 80 60 30 
== 最小值: 10
== 最大值: 90
== 樹的詳細信息: 
30(B) is root
10(B) is 30's   left child
20(R) is 10's  right child
60(R) is 30's  right child
40(B) is 60's   left child
50(R) is 40's  right child
80(B) is 60's  right child
70(R) is 80's   left child
90(R) is 80's  right child
複製代碼

 


發佈了26 篇原創文章 · 獲贊 79 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章