紅黑樹(四)之 C++的實現

 

概要

前面分別介紹紅黑樹的理論知識紅黑樹的C語言實現。本章是紅黑樹的C++實現,若讀者對紅黑樹的理論知識不熟悉,創建先學習紅黑樹的理論知識,再來學習本章。html

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

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


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

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

 

紅黑樹的介紹

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

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

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

紅黑樹示意圖以下:學習

 

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

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

 

1. 基本定義

enum RBTColor{RED, BLACK};

template <class T>
class RBTNode{
    public:
        RBTColor color;    // 顏色
        T key;            // 關鍵字(鍵值)
        RBTNode *left;    // 左孩子
        RBTNode *right;    // 右孩子
        RBTNode *parent; // 父結點

        RBTNode(T value, RBTColor c, RBTNode *p, RBTNode *l, RBTNode *r):
            key(value),color(c),parent(),left(l),right(r) {}
};

template <class T>
class RBTree {
    private:
        RBTNode<T> *mRoot;    // 根結點

    public:
        RBTree();
        ~RBTree();

        // 前序遍歷"紅黑樹"
        void preOrder();
        // 中序遍歷"紅黑樹"
        void inOrder();
        // 後序遍歷"紅黑樹"
        void postOrder();

        // (遞歸實現)查找"紅黑樹"中鍵值爲key的節點
        RBTNode<T>* search(T key);
        // (非遞歸實現)查找"紅黑樹"中鍵值爲key的節點
        RBTNode<T>* iterativeSearch(T key);

        // 查找最小結點:返回最小結點的鍵值。
        T minimum();
        // 查找最大結點:返回最大結點的鍵值。
        T maximum();

        // 找結點(x)的後繼結點。即,查找"紅黑樹中數據值大於該結點"的"最小結點"。
        RBTNode<T>* successor(RBTNode<T> *x);
        // 找結點(x)的前驅結點。即,查找"紅黑樹中數據值小於該結點"的"最大結點"。
        RBTNode<T>* predecessor(RBTNode<T> *x);

        // 將結點(key爲節點鍵值)插入到紅黑樹中
        void insert(T key);

        // 刪除結點(key爲節點鍵值)
        void remove(T key);

        // 銷燬紅黑樹
        void destroy();

        // 打印紅黑樹
        void print();
    private:
        // 前序遍歷"紅黑樹"
        void preOrder(RBTNode<T>* tree) const;
        // 中序遍歷"紅黑樹"
        void inOrder(RBTNode<T>* tree) const;
        // 後序遍歷"紅黑樹"
        void postOrder(RBTNode<T>* tree) const;

        // (遞歸實現)查找"紅黑樹x"中鍵值爲key的節點
        RBTNode<T>* search(RBTNode<T>* x, T key) const;
        // (非遞歸實現)查找"紅黑樹x"中鍵值爲key的節點
        RBTNode<T>* iterativeSearch(RBTNode<T>* x, T key) const;

        // 查找最小結點:返回tree爲根結點的紅黑樹的最小結點。
        RBTNode<T>* minimum(RBTNode<T>* tree);
        // 查找最大結點:返回tree爲根結點的紅黑樹的最大結點。
        RBTNode<T>* maximum(RBTNode<T>* tree);

        // 左旋
        void leftRotate(RBTNode<T>* &root, RBTNode<T>* x);
        // 右旋
        void rightRotate(RBTNode<T>* &root, RBTNode<T>* y);
        // 插入函數
        void insert(RBTNode<T>* &root, RBTNode<T>* node);
        // 插入修正函數
        void insertFixUp(RBTNode<T>* &root, RBTNode<T>* node);
        // 刪除函數
        void remove(RBTNode<T>* &root, RBTNode<T> *node);
        // 刪除修正函數
        void removeFixUp(RBTNode<T>* &root, RBTNode<T> *node, RBTNode<T> *parent);

        // 銷燬紅黑樹
        void destroy(RBTNode<T>* &tree);

        // 打印紅黑樹
        void print(RBTNode<T>* tree, T key, int direction);

#define rb_parent(r)   ((r)->parent)
#define rb_color(r) ((r)->color)
#define rb_is_red(r)   ((r)->color==RED)
#define rb_is_black(r)  ((r)->color==BLACK)
#define rb_set_black(r)  do { (r)->color = BLACK; } while (0)
#define rb_set_red(r)  do { (r)->color = RED; } while (0)
#define rb_set_parent(r,p)  do { (r)->parent = (p); } while (0)
#define rb_set_color(r,c)  do { (r)->color = (c); } while (0)
};

RBTNode是紅黑樹的節點類,而RBTree對應是紅黑樹的操做實現類。在RBTree中包含了根節點mRoot和紅黑樹的相關API。
注意:(01) 在實現紅黑樹API的過程當中,我重載了許多函數。重載的緣由,一是由於有的API是內部接口,有的是外部接口;二是爲了讓結構更加清晰。
          (02) 因爲C++的實現是在上一篇介紹的"C語言"實現基礎上移植而來,在該代碼中,保留了一些C語言的特性;例如(宏定義)。

 

2. 左旋

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

 

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

/* 
 * 對紅黑樹的節點(x)進行左旋轉
 *
 * 左旋示意圖(對節點x進行左旋):
 *      px                              px
 *     /                               /
 *    x                               y                
 *   /  \      --(左旋)-->           / \                #
 *  lx   y                          x  ry     
 *     /   \                       /  \
 *    ly   ry                     lx  ly  
 *
 *
 */
template <class T>
void RBTree<T>::leftRotate(RBTNode<T>* &root, RBTNode<T>* x)
{
    // 設置x的右孩子爲y
    RBTNode<T> *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)
    {
        root = 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
 * 
 */
template <class T>
void RBTree<T>::rightRotate(RBTNode<T>* &root, RBTNode<T>* y)
{
    // 設置x是當前節點的左孩子。
    RBTNode<T> *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) 
    {
        root = 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. 添加

將一個節點插入到紅黑樹中,須要執行哪些步驟呢?首先,將紅黑樹看成一顆二叉查找樹,將節點插入;而後,將節點着色爲紅色;最後,經過"旋轉和從新着色"等一系列操做來修正該樹,使之從新成爲一顆紅黑樹。詳細描述以下:
第一步: 將紅黑樹看成一顆二叉查找樹,將節點插入。
       紅黑樹自己就是一顆二叉查找樹,將節點插入後,該樹仍然是一顆二叉查找樹。也就意味着,樹的鍵值仍然是有序的。此外,不管是左旋仍是右旋,若旋轉以前這棵樹是二叉查找樹,旋轉以後它必定仍是二叉查找樹。這也就意味着,任何的旋轉和從新着色操做,都不會改變它仍然是一顆二叉查找樹的事實。
      好吧?那接下來,咱們就來千方百計的旋轉以及從新着色,使這顆樹從新成爲紅黑樹!

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

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


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

/* 
 * 將結點插入到紅黑樹中
 *
 * 參數說明:
 *     root 紅黑樹的根結點
 *     node 插入的結點        // 對應《算法導論》中的node
 */
template <class T>
void RBTree<T>::insert(RBTNode<T>* &root, RBTNode<T>* node)
{
    RBTNode<T> *y = NULL;
    RBTNode<T> *x = root;

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

    node->parent = y;
    if (y!=NULL)
    {
        if (node->key < y->key)
            y->left = node;
        else
            y->right = node;
    }
    else
        root = node;

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

    // 3. 將它從新修正爲一顆二叉查找樹
    insertFixUp(root, node);
}

/* 
 * 將結點(key爲節點鍵值)插入到紅黑樹中
 *
 * 參數說明:
 *     tree 紅黑樹的根結點
 *     key 插入結點的鍵值
 */
template <class T>
void RBTree<T>::insert(T key)
{
    RBTNode<T> *z=NULL;

    // 若是新建結點失敗,則返回。
    if ((z=new RBTNode<T>(key,BLACK,NULL,NULL,NULL)) == NULL)
        return ;

    insert(mRoot, z);
}

內部接口 -- insert(root, node)的做用是將"node"節點插入到紅黑樹中。其中,root是根,node是被插入節點。
外部接口 -- insert(key)的做用是將"key"添加到紅黑樹中。


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

/*
 * 紅黑樹插入修正函數
 *
 * 在向紅黑樹中插入節點以後(失去平衡),再調用該函數;
 * 目的是將它從新塑形成一顆紅黑樹。
 *
 * 參數說明:
 *     root 紅黑樹的根
 *     node 插入的結點        // 對應《算法導論》中的z
 */
template <class T>
void RBTree<T>::insertFixUp(RBTNode<T>* &root, RBTNode<T>* node)
{
    RBTNode<T> *parent, *gparent;

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

        //若「父節點」是「祖父節點的左孩子」
        if (parent == gparent->left)
        {
            // Case 1條件:叔叔節點是紅色
            {
                RBTNode<T> *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)
            {
                RBTNode<T> *tmp;
                leftRotate(root, parent);
                tmp = parent;
                parent = node;
                node = tmp;
            }

            // Case 3條件:叔叔是黑色,且當前節點是左孩子。
            rb_set_black(parent);
            rb_set_red(gparent);
            rightRotate(root, gparent);
        } 
        else//若「z的父節點」是「z的祖父節點的右孩子」
        {
            // Case 1條件:叔叔節點是紅色
            {
                RBTNode<T> *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)
            {
                RBTNode<T> *tmp;
                rightRotate(root, parent);
                tmp = parent;
                parent = node;
                node = tmp;
            }

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

    // 將根節點設爲黑色
    rb_set_black(root);
}

insertFixUp(root, node)的做用是對應"上面所講的第三步"。它是一個內部接口。

 

5. 刪除操做

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

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

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


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

/* 
 * 刪除結點(node),並返回被刪除的結點
 *
 * 參數說明:
 *     root 紅黑樹的根結點
 *     node 刪除的結點
 */
template <class T>
void RBTree<T>::remove(RBTNode<T>* &root, RBTNode<T> *node)
{
    RBTNode<T> *child, *parent;
    RBTColor color;

    // 被刪除節點的"左右孩子都不爲空"的狀況。
    if ( (node->left!=NULL) && (node->right!=NULL) ) 
    {
        // 被刪節點的後繼節點。(稱爲"取代節點")
        // 用它來取代"被刪節點"的位置,而後再將"被刪節點"去掉。
        RBTNode<T> *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 = 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)
            removeFixUp(root, child, parent);

        delete 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 = child;

    if (color == BLACK)
        removeFixUp(root, child, parent);
    delete node;
}

/* 
 * 刪除紅黑樹中鍵值爲key的節點
 *
 * 參數說明:
 *     tree 紅黑樹的根結點
 */
template <class T>
void RBTree<T>::remove(T key)
{
    RBTNode<T> *node; 

    // 查找key對應的節點(node),找到的話就刪除該節點
    if ((node = search(mRoot, key)) != NULL)
        remove(mRoot, node);
}

內部接口 -- remove(root, node)的做用是將"node"節點插入到紅黑樹中。其中,root是根,node是被插入節點。
外部接口 -- remove(key)刪除紅黑樹中鍵值爲key的節點。


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

/*
 * 紅黑樹刪除修正函數
 *
 * 在從紅黑樹中刪除插入節點以後(紅黑樹失去平衡),再調用該函數;
 * 目的是將它從新塑形成一顆紅黑樹。
 *
 * 參數說明:
 *     root 紅黑樹的根
 *     node 待修正的節點
 */
template <class T>
void RBTree<T>::removeFixUp(RBTNode<T>* &root, RBTNode<T> *node, RBTNode<T> *parent)
{
    RBTNode<T> *other;

    while ((!node || rb_is_black(node)) && node != root)
    {
        if (parent->left == node)
        {
            other = parent->right;
            if (rb_is_red(other))
            {
                // Case 1: x的兄弟w是紅色的  
                rb_set_black(other);
                rb_set_red(parent);
                leftRotate(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);
                    rightRotate(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);
                leftRotate(root, parent);
                node = root;
                break;
            }
        }
        else
        {
            other = parent->left;
            if (rb_is_red(other))
            {
                // Case 1: x的兄弟w是紅色的  
                rb_set_black(other);
                rb_set_red(parent);
                rightRotate(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);
                    leftRotate(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);
                rightRotate(root, parent);
                node = root;
                break;
            }
        }
    }
    if (node)
        rb_set_black(node);
}

removeFixup(root, node, parent)是對應"上面所講的第三步"。它是一個內部接口。

 

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

下面是紅黑樹實現的完整代碼和相應的測試程序。
(1) 除了上面所說的"左旋"、"右旋"、"添加"、"刪除"等基本操做以後,還實現了"遍歷"、"查找"、"打印"、"最小值"、"最大值"、"建立"、"銷燬"等接口。
(2) 函數接口大多分爲內部接口和外部接口。內部接口是private函數,外部接口則是public函數。
(3) 測試代碼中提供了"插入"和"刪除"動做的檢測開關。默認是關閉的,打開方法能夠參考"代碼中的說明"。建議在打開開關後,在草稿上本身動手繪製一下紅黑樹。

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

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

紅黑樹的測試文件(RBTreeTest.cpp)

 1 /**
 2  * C++ 語言: 二叉查找樹
 3  *
 4  * @author skywang
 5  * @date 2013/11/07
 6  */
 7 
 8 #include <iostream>
 9 #include "RBTree.h"
10 using namespace std;
11 
12 int main()
13 {
14     int a[]= {10, 40, 30, 60, 90, 70, 20, 50, 80};
15     int check_insert=0;    // "插入"動做的檢測開關(0,關閉;1,打開)
16     int check_remove=0;    // "刪除"動做的檢測開關(0,關閉;1,打開)
17     int i;
18     int ilen = (sizeof(a)) / (sizeof(a[0])) ;
19     RBTree<int>* tree=new RBTree<int>();
20 
21     cout << "== 原始數據: ";
22     for(i=0; i<ilen; i++)
23         cout << a[i] <<" ";
24     cout << endl;
25 
26     for(i=0; i<ilen; i++) 
27     {
28         tree->insert(a[i]);
29         // 設置check_insert=1,測試"添加函數"
30         if(check_insert)
31         {
32             cout << "== 添加節點: " << a[i] << endl;
33             cout << "== 樹的詳細信息: " << endl;
34             tree->print();
35             cout << endl;
36         }
37 
38     }
39 
40     cout << "== 前序遍歷: ";
41     tree->preOrder();
42 
43     cout << "\n== 中序遍歷: ";
44     tree->inOrder();
45 
46     cout << "\n== 後序遍歷: ";
47     tree->postOrder();
48     cout << endl;
49 
50     cout << "== 最小值: " << tree->minimum() << endl;
51     cout << "== 最大值: " << tree->maximum() << endl;
52     cout << "== 樹的詳細信息: " << endl;
53     tree->print();
54 
55     // 設置check_remove=1,測試"刪除函數"
56     if(check_remove)
57     {
58         for(i=0; i<ilen; i++)
59         {
60             tree->remove(a[i]);
61 
62             cout << "== 刪除節點: " << a[i] << endl;
63             cout << "== 樹的詳細信息: " << endl;
64             tree->print();
65             cout << endl;
66         }
67     }
68 
69     // 銷燬紅黑樹
70     tree->destroy();
71 
72     return 0;
73 }
View Code

 

紅黑樹的C++測試程序

測試程序已經包含在相應的實現文件(MaxHeap.cpp)中了,這裏就再也不重複說明。下面是測試程序的運行結果:

== 原始數據: 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
相關文章
相關標籤/搜索