• 红黑树(四)之 C++的实现


    概要

    前面分别介绍红黑树的理论知识红黑树的C语言实现。本章是红黑树的C++实现,若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章。

    目录
    1. 红黑树的介绍
    2. 红黑树的C++实现(代码说明)
    3. 红黑树的C++实现(完整源码)
    4. 红黑树的C++测试程序

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3624291.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. 基本定义

    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 << "
    == 中序遍历: ";
    44     tree->inOrder();
    45 
    46     cout << "
    == 后序遍历: ";
    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
  • 相关阅读:
    数据库
    计算机基础知识系列
    《大话数据结构》参考
    数据结构与算法系列
    python cookbook
    Python教程 廖雪峰
    Python入门学习系列
    认识 React——声明式,高效且灵活的用于构建用户界面的 JavaScript 库
    线程---同步(synchronized)
    线程---插队和礼让执行(join和yield)
  • 原文地址:https://www.cnblogs.com/skywang12345/p/3624291.html
Copyright © 2020-2023  润新知