现在的位置: 首页 > 综合 > 正文

红黑树理论与c++实现

2013年08月25日 ⁄ 综合 ⁄ 共 14685字 ⁄ 字号 评论关闭
    红黑树(Red-Black Tree)是二叉搜索树(Binary Search Tree)的一种改进。我们知道二叉搜索树在最坏的情况下可能会变成一个链表(当所有节点按从小到大的顺序依次插入后)。而红黑树在每一次插入或删除节点之后都会花O(log N)的时间来对树的结构作修改,以保持树的平衡。也就是说,红黑树的查找方法与二叉搜索树完全一样;插入和删除节点的的方法前半部分节与二叉搜索树完全一样,而后半部分添加了一些修改树的结构的操作。

    红黑树的每个节点上的属性除了有一个key、3个指针:parent、lchild、rchild以外,还多了一个属性:color。它只能是两种颜色:红或黑。而红黑树除了具有二叉搜索树的所有性质之外,还具有以下4点性质:

1. 根节点是黑色的。
2. 空节点是黑色的(红黑树中,根节点的parent以及所有叶节点lchild、rchild都不指向NULL,而是指向一个定义好的空节点)。
3. 红色节点的父、左子、右子节点都是黑色。
4. 在任何一棵子树中,每一条从根节点向下走到空节点的路径上包含的黑色节点数量都相同。

     

    这些约束强制了红黑树的关键属性: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值都要求与树的高度成比例的最坏情况时间,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。

        要知道为什么这些特性确保了这个结果,注意到属性4导致了路径不能有两个毗连的红色节点就足够了。最短的可能路径都是黑色节点,最长的可能路径有交替的红色和黑色节点。因为根据属性5所有最长的路径都有相同数目的黑色节点,这就表明了没有路径能多于任何其他路径的两倍长。

        在很多树数据结构的表示中,一个节点有可能只有一个儿子,而叶子节点包含数据。用这种范例表示红黑树是可能的,但是这会改变一些属性并使算法复杂。为此,本文中我们使用 "nil 叶子" "(null)叶子",如上图所示,它不包含数据而只充当树在此结束的指示。这些节点在绘图中经常被省略,导致了这些树好象同上述原则相矛盾,而实际上不是这样。与此有关的结论是所有节点都有两个儿子,尽管其中的一个或两个可能是空叶子。

如下图就是一棵红黑树:

有了这几条规则,就可以保证整棵树的平衡,也就等于保证了搜索的时间为O(log N)。

但是在插入、删除节点后,就有可能破坏了红黑树的性质。所以我们要做一些操作来把整棵树修补好。下面我就来介绍一下。

首先有一个预备知识,那就是节点的Left-Rotate和Right-Rotate操作。所谓Left-Rotate(x)就是把节点x向左下方向移动一格,然后让x原来的右子节点代替它的位置。而Right-Rotate当然就是把Left-Rotate左、右互反一下。如下图:

注意,Left-Rotate(x)后,x的右子树变成了原来y的左子树,Right-Rotate反之。思考一下,这样一次变换后,仍然满足二叉搜索树的性质。在红黑树的插入、删除中,要用到很多Left-Rotate和Right-Rotate操作。

一、 插入

插入首先是按部就班二叉搜索树的插入步骤,把新节点z插入到某一个叶节点的位置上。
接下来把z的颜色设成红色。为什么?还记得红黑树的性质吗,从根节点向下到空节点的每一条路径上的黑色节点数要相同。如果新插入的是黑色节点,那么它所在的路径上就多出了一个黑色的节点了。所以新插入的节点一定要设成红色。但是这样可能又有一个矛盾,如果z的父节点也是红色,怎么办,前面说过红色节点的子节点必须是黑色。因此我们要执行下面一个迭代的过程,称为Insert-Fixup,来修补这棵红黑树。

在Insert-Fixup中,每一次迭代的开始,指针z一定都指向一个红色的节点。如果z->parent是黑色,那我们就大功告成了;如果z->parent是红色,显然这就违返了红黑的树性质,那么我们要想办法把z或者z->parent变成黑色,但这要建立在不破坏红黑树的其他性质的基础上。

这里再引入两个指针:grandfather,指向z->parent->parent,也就是z的爷爷(显然由于z->parent为红色,grandfather一定是黑色);uncle,指向grandfather除了z->parent之外的另一个子节点,也就是z的父亲的兄弟,所以叫uncle。

(为了说话方便,我们这里都假设z->parent是grandfather的左子节点,而uncle是grandfather的右子节点。如果遇到的实际情况不是这样,那也只要把所有操作中的左、右互反就可以了。)

在每一次迭代中,我们可能遇到以下三种情况。
Case 1. uncle也是红色。这时只要把z->parent和uncle都设成黑色,并把grandfather设成红色。这样仍然确保了每一条路径上的黑色节点数不变。然后把z指向grandfather,并开始新一轮的迭代。如下图:

Case 2. uncle是黑色,并且z是z->parent的右子节点。这时我们只要把z指向z->parent,然后做一次Left-Rotate(z)。就可以把情况转化成Case 3。

Case 3. uncle是黑色,并且z是z->parent的左子节点。到了这一步,我们就剩最后一步了。只要把z->parent设成黑色,把grandfather设成红色,再做一次Right-Rotate(grandfather),整棵树就修补完毕了。可以思考一下,这样一次操作之后,确实满足了所有红黑树的性质。Case 2和Case 3如下图:

反复进行迭代,直到某一次迭代开始时z->parent为黑色而告终,也就是当遇到Case 3后,做完它而告终。

二、删除

让我们来回顾一下二叉搜索树的删除节点z的过程:如果z没有子节点,那么直接删除即可;如果z只有一个子节点,那么让这个子节点来代替z的位置,然后把z删除即可;如果z有两个子节点,那么找到z在中序遍历中的后继节点s(也就是从z->rchild开始向左下方一直走到底的那一个节点),把s的key赋值给z的key,然后删除s。

红黑树中删除一个节点z的方法也是首先按部就班以上的过程。
如果删除的节点是黑色的,那么显然它所在的路径上就少一个黑色节点,那么红黑树的性质就被破坏了。这时我们就要执行一个称为Delete-Fixup的过程,来修补这棵树。下面我就来讲解一下。

一个节点被删除之后(实际删除的节点是上面的s,不是本来key对应的节点),一定有一个它的子节点代替了它的位置(即使是叶节点被删除后,也会有一个空节点来代替它的位置。前面说过,在红黑树中,空节点是一个实际存在的节点。)。我们就设指针x指向这个代替位置的节点(删除节点这个位置已经被替代了)。
显然,如果x是红色的,那么我们只要把它设成黑色,它所在的路径上就重新多出了一个黑色节点,那么红黑树的性质就满足了。
然而,如果x是黑色的,那我们就要假想x上背负了2个单位的黑色。那么红黑树的性质也同样不破坏,但是我们要找到某一个红色的节点,把x上“超载”的这1个单位的黑色丢给它,这样才算完成。Delete-Fixup做的就是这个工作。

Delete-Fixup同样是一个循环迭代的过程。每一次迭代开始时,如果指针x指向一个红色节点,那么大功告成,把它设成黑色即告终。相反如果x黑色,那么我们就会面对以下4种情况。

这里引入另一个指针w,指向x的兄弟。这里我们都默认x是x->parent的左子节点,则w是x->parent的右子节点。(如果实际遇到相反的情况,只要把所有操作中的左、右互反一下就可以了。)

Case 1. w是红色。这时我们根据红黑树的性质可以肯定x->parent是黑色、w->lchild是黑色。我们把x->parent与w的颜色互换,然后做一次Left-Rotate(x->parent)。做完之后x就有了一个新的兄弟:原w->lchild,前面说过它一定是黑色的。那么我们就在不破坏红黑树性质的前提下,把Case 1转换成了Case2、3、4中的一个,也就是w是黑色的情况。思考一下,这样做不会改变每条路径上黑色节点的个数,如下图:

Case 2. w是黑色,并且w的两个子节点都是黑色。这时我们只要把w设成红色。然后把x移到x->parent,开始下一轮迭代(注意,那“超载”的1单位的黑色始终是跟着指针x走的,直到x走到了一个红色节点上才能把它“卸下”)。思考一下,这一次操作不会破坏红黑树的性质。如下图(图中节点B不一定是红色,也可能是黑色):

Case 3. w是黑色,并且w的两个子节点左红右黑。这时我们把w与w->lchild的颜色互换,然后做Right-Rotate(w)。思考一下,这样做之后不会破坏红黑树的性质。这时x的新的兄弟就是原w->lchild。而Case 3被转化成了Case 4。

Case 4. w是黑色,并且w的右子节点是红色。一但遇到Case 4,就胜利在望了。我看下面一张图。先把w与x->parent的颜色互换,再做Left-Rotate(x->parent)。这时图中节点E(也就是原w->rchild)所在的路径就肯定少了一个黑色,而x所在的路径则多了一个黑色。那么我们就把x上多余的1个单位的黑色丢给E就可以了。至此,Delete-Fixup就顺利完成了。

  1. /*
  2.  * File: rbtree.h 
  3.  * Purpose: interface for RBTree
  4.  * Author: cxf
  5.  * Date: 06/08/2008
  6.  */
  7. #ifndef _RBTREE_H_
  8. #define _RBTREE_H_
  9. #include <iostream>
  10. using namespace std;
  11. //节点的颜色(红或黑)
  12. typedef enum
  13. {
  14.     BLACK,
  15.     RED
  16. }NodeColor;
  17. typedef enum
  18. {
  19.     RBT_STATUS_OK,
  20.     RBT_STATUS_KEY_NOT_FOUND,
  21.     RBT_STATUS_MEM_EXAUSTED,
  22.     RBT_STATUS_KEY_DUPLICATE
  23. }RBtStatus;
  24. typedef  int KeyType;
  25. typedef  int ValueType;
  26. //比较两个节点key的大小
  27. #define compLT(a, b) ((a) < (b))
  28. #define compEQ(a, b) ((a) == (b))
  29. //红黑树节点类
  30. class RBTreeNode
  31. {
  32. public:
  33.     RBTreeNode(NodeColor _color = BLACK, RBTreeNode *_left = NULL, RBTreeNode *_right = NULL, /
  34.                RBTreeNode *_parent = NULL, KeyType _key = INT_MAX, ValueType _value = 0);
  35.     friend class RBTree;
  36. private:
  37.     NodeColor color;
  38.     RBTreeNode *left;
  39.     RBTreeNode *right;
  40.     RBTreeNode *parent;
  41.     KeyType key;
  42.     ValueType value;
  43. };
  44. //红黑树类
  45. class RBTree
  46. {
  47. public:
  48.     RBTree(RBTreeNode *_root = NULL);
  49.     ~RBTree();
  50.     int Insert(KeyType key, ValueType value);//插入节点
  51.     int Delete(KeyType key); //删除对应键的节点
  52.     RBTreeNode* Search(KeyType key);//查找特定键
  53.     void InOrder(); //中序遍历树
  54. private:
  55.     RBTreeNode *root;
  56.     void InsertFixup(RBTreeNode *x);//插入节点修正函数
  57.     void DeleteFixup(RBTreeNode *x);//删除节点修正函数
  58.     void RotateLeft(RBTreeNode *x); //左旋转
  59.     void RotateRight(RBTreeNode *x);//右旋转
  60.     void Destroy(RBTreeNode *x);
  61.     void Display(RBTreeNode *x);
  62.     void InOrder(RBTreeNode *y, void (RBTree::*callback)(RBTreeNode*));
  63. };
  64. #endif
  65. /*
  66.  * File: rbtree.cpp 
  67.  * Purpose: implemention for RBTree
  68.  * Author: cxf
  69.  * Date: 06/08/2008
  70.  */
  71. #include <cassert>
  72. #include "rbtree.h"
  73. RBTreeNode::RBTreeNode(NodeColor _color /* = BLACK */, RBTreeNode *_left /* = NULL */, /
  74.                        RBTreeNode *_right /* = NULL */, RBTreeNode *_parent /* = NULL */, /
  75.                        KeyType _key /* = INT_MAX */, ValueType _value /* = 0 */)
  76. {
  77.     color = _color;
  78.     left = _left;
  79.     right = _right;
  80.     parent = _parent;
  81.     key = _key;
  82.     value = _value;
  83. }
  84. RBTree::RBTree(RBTreeNode *_root /* = NULL */)
  85. {
  86.     root = _root;
  87. }
  88. RBTree::~RBTree()
  89. {
  90.     Destroy(root);
  91. }
  92. //销毁从x节点开始的所有树中节点
  93. void RBTree::Destroy(RBTreeNode *x)
  94. {
  95.     if (NULL == x)
  96.     {
  97.         return;
  98.     }
  99.     Destroy(x->left);
  100.     Destroy(x->right);
  101.     free(x);
  102. }
  103. /*------------------------------------------------
  104. |   x              y
  105. |  / /    ==>     / / 
  106. | a   y          x   c 
  107. |    / /        / / 
  108. |    b  c       a  b 
  109. ------------------------------------------------*/ 
  110. void RBTree::RotateLeft(RBTreeNode *x)
  111. {
  112.     assert(x != NULL);
  113.     
  114.     RBTreeNode *y = x->right;
  115.     x->right = y->left;
  116.     if (y->left != NULL)
  117.     {
  118.         y->left->parent = x;
  119.     }
  120.     
  121.     if (x == root)
  122.     {
  123.         root = y;
  124.     }
  125.     else
  126.     {
  127.         y->parent = x->parent;      
  128.         if (x == x->parent->left)
  129.         {
  130.             x->parent->left = y;
  131.         }
  132.         else
  133.         {
  134.             x->parent->right = y;
  135.         }
  136.     }
  137.     
  138.     y->left = x;
  139.     x->parent = y;
  140. }
  141. /*------------------------------------------------
  142. |    x              y 
  143. |   / /            / / 
  144. |  y   c   ==>    a   x 
  145. | / /                / / 
  146. |a   b              b   c 
  147. -------------------------------------------------*/ 
  148. void RBTree::RotateRight(RBTreeNode *x)
  149. {
  150.     assert(x != NULL);
  151.     RBTreeNode *y = x->left;
  152.     x->left = y->right;
  153.     if (y->right != NULL)
  154.     {
  155.         y->right->parent = x;
  156.     }
  157.     
  158.     if (root == x)
  159.     {
  160.         root = y;
  161.     }
  162.     else
  163.     {
  164.         y->parent = x->parent;
  165.         if (x == x->parent->left)
  166.         {
  167.             x->parent->left = y;
  168.         }
  169.         else
  170.         {
  171.             x->parent->right = y;
  172.         }
  173.     }
  174.     
  175.     y->right = x;
  176.     x->parent = y;
  177. }
  178. //在树中查找键为key的节点
  179. RBTreeNode* RBTree::Search(KeyType key)
  180. {
  181.     RBTreeNode *p = root;
  182.     RBTreeNode *pp = NULL;
  183.     while (p != NULL)
  184.     {
  185.         pp = p;
  186.         if (compEQ(key, p->key))
  187.         {
  188.             break;
  189.         }
  190.         p = compLT(key, p->key) ? p->left : p->right;       
  191.     }
  192.     return p;
  193. }
  194. int RBTree::Insert(KeyType key, ValueType value)
  195. {
  196.     RBTreeNode *p = root;
  197.     RBTreeNode *pp = NULL;
  198.     //寻找插入位置,循环结束时,pp保存插入节点的父节点
  199.     while (p != NULL)
  200.     {
  201.         pp = p;
  202.         if (compEQ(key, p->key))
  203.         {
  204.             return RBT_STATUS_KEY_DUPLICATE;
  205.         }
  206.         p = compLT(key, p->key) ? p->left : p->right;       
  207.     }
  208.     
  209.     //若是空树,将节点设为黑色
  210.     if (NULL == root)
  211.     {
  212.         root = p = new RBTreeNode(BLACK, NULL, NULL, NULL, key, value);
  213.     }
  214.     //若树非空,将节点设为红色并插入
  215.     else
  216.     {
  217.         p = new RBTreeNode(RED, NULL, NULL, pp, key, value);
  218.         if (compLT(key, pp->key))
  219.         {
  220.             pp->left = p;
  221.         }
  222.         else
  223.         {
  224.             pp->right = p;
  225.         }   
  226.     }
  227.     //插入后,进行修正,以符合红黑树的特点
  228.     InsertFixup(p);
  229.     return RBT_STATUS_OK;
  230. }
  231. //插入节点后修正函数
  232. void RBTree::InsertFixup(RBTreeNode *x)
  233. {
  234.     RBTreeNode *uncle = NULL; //x的叔叔节点
  235.     
  236.     //循环直到x的父节点是黑色或x为根结点即可
  237.     while (x != root && RED == x->parent->color)
  238.     {
  239.         //叔叔在爷爷的右子树上
  240.         if (x->parent == x->parent->parent->left)
  241.         {
  242.             uncle = x->parent->parent->right;
  243.             //叔叔节点为红色,或没有叔叔节点
  244.             if (uncle != NULL && RED == uncle->color)
  245.             {
  246.                 x->parent->color = BLACK;
  247.                 x->parent->parent->color = RED;
  248.                 uncle->color = BLACK;
  249.                 x = x->parent->parent;
  250.             }
  251.             //叔叔节点为黑色
  252.             else
  253.             {
  254.                 //x在右子树上,需要转换为x在左子树上
  255.                 if (x == x->parent->right)
  256.                 {
  257.                     x = x->parent;
  258.                     RotateLeft(x);
  259.                 }
  260.                 //x在左子树上
  261.                 x->parent->color = BLACK;
  262.                 x->parent->parent->color = RED;
  263.                 RotateRight(x->parent->parent);
  264.             }
  265.         }
  266.         //叔叔在爷爷的左子树上,与上面算法基本相同,旋转方向需要改变
  267.         else
  268.         {
  269.             uncle = x->parent->parent->left;
  270.             if (uncle != NULL && RED == uncle->color)
  271.             {
  272.                 x->parent->color = BLACK;
  273.                 x->parent->parent->color = RED;
  274.                 uncle->color = BLACK;
  275.                 x = x->parent->parent;
  276.             }
  277.             else
  278.             {
  279.                 if (x == x->parent->left)
  280.                 {
  281.                     x = x->parent;
  282.                     RotateRight(x);
  283.                 }
  284.                 x->parent->color = BLACK;
  285.                 x->parent->parent->color = RED;
  286.                 RotateLeft(x->parent->parent);
  287.             }
  288.         }
  289.     }
  290.     //一定要加这一句,因为可能最后x指向了root,且root的颜色可能被修改过,这时只要将根设为黑色即可
  291.     root->color = BLACK;
  292. }
  293. //删除键为key的节点
  294. int RBTree::Delete(KeyType key)
  295. {
  296.     RBTreeNode *p = NULL; //指向查找到的节点(实际上可能并不删除它)
  297.     RBTreeNode *x = NULL; //指向欲删除的节点(可能和p一样)
  298.     RBTreeNode *y = NULL; //指向欲删除节点的子节点(欲删除节点只有一个子节点)
  299.     // 先寻找节点,并用p指向
  300.     if (NULL == (p = Search(key)))
  301.     {
  302.         return RBT_STATUS_KEY_NOT_FOUND;
  303.     }
  304.     //p的两个子节点可能存在或不存在,两种情况下用x统一保存真正需要删除的节点
  305.     if (NULL == p->left || NULL == p->right)
  306.     {
  307.         x = p;
  308.     }
  309.     else
  310.     {
  311.         x = p->right;
  312.         while (x->left != NULL)
  313.         {
  314.             x = x->left;
  315.         }
  316.     }
  317.     //y保存需要删除节点x的子节点
  318.     if (NULL == x->left)
  319.     {
  320.         y = x->right;
  321.     }
  322.     else
  323.     {
  324.         y = x->left;
  325.     }
  326.     //删除的节点不是根节点
  327.     if (x != root)
  328.     {
  329.         if (y != NULL)
  330.         {
  331.             y->parent = x->parent;
  332.         }   
  333.         if (x == x->parent->left)
  334.         {
  335.             x->parent->left = y;
  336.         }
  337.         else
  338.         {
  339.             x->parent->right = y;
  340.         }
  341.         
  342.         if (BLACK == x->color)
  343.         {
  344.             if (y != NULL)
  345.             {
  346.                 DeleteFixup(y);
  347.             }
  348.             else
  349.             {
  350.                 DeleteFixup(x->parent);
  351.             }           
  352.         }   
  353.     }
  354.     //删除的节点是根节点
  355.     else
  356.     {
  357.         root = y;
  358.         if (y != NULL)
  359.         {
  360.             y->color = BLACK;
  361.         }       
  362.     }
  363.     //用"实际被删除节点"的值取代"表面上删除节点"的值
  364.     if ( x != p)
  365.     {
  366.         p->key = x->key;
  367.         p->value = x->value;
  368.     }
  369.     
  370.     delete x;
  371.     return RBT_STATUS_OK;
  372. }
  373. //删除节点修正函数(有bug,但不知怎样修正: 当x没有兄弟节点时即silbing为空时。)
  374. void RBTree::DeleteFixup(RBTreeNode *x)
  375. {
  376.     
  377.     RBTreeNode *sibling = NULL;//节点x的兄弟节点
  378.     //一直循环,直到x是根节点或x节点为红色,这时直接将x设为黑色即可
  379.     while ((x != root) && (x->color == BLACK))
  380.     {
  381.         //节点x在其父亲的左子树上
  382.         if (x == x->parent->left)
  383.         {
  384.             sibling = x->parent->right;
  385.             //兄弟颜色为红色,转换为兄弟为黑色的情况
  386.             if (RED == sibling->color)
  387.             {
  388.                 x->parent->color = RED;
  389.                 sibling->color = BLACK;
  390.                 RotateLeft(x->parent);
  391.                 sibling = x->parent->right;
  392.             }
  393.             //兄弟颜色为黑色
  394.             
  395.             //兄弟的两个子树均为黑色, 空节点算黑节点
  396.             if ((NULL == sibling->left || BLACK == sibling->left->color) && /
  397.                 (NULL == sibling->right || BLACK == sibling->right->color))
  398.             {
  399.                 sibling->color = RED;
  400.                 x = x->parent;
  401.             }               
  402.             else
  403.             {
  404.                 //兄弟的两个子树中左红右黑,将其转换为右子树为红色
  405.                 if ((NULL == sibling->right) || (BLACK == sibling->right->color))
  406.                 {
  407.                     sibling->color = RED;
  408.                     sibling->left->color = BLACK;
  409.                     RotateRight(sibling);
  410.                     sibling = x->parent->right;
  411.                 }   
  412.                 //兄弟的右子树为红
  413.                 sibling->color = x->parent->color;
  414.                 x->parent->color = BLACK;   
  415.                 sibling->right->color = BLACK;
  416.                 RotateLeft(x->parent);  
  417.                 break;
  418.             }
  419.             
  420.         }
  421.         //节点x在其父亲的右子树上, 算法与上面相同,只是旋转方向需要改变
  422.         else
  423.         {
  424.             sibling = x->parent->left;
  425.             if (RED == sibling->color)
  426.             {
  427.                 x->parent->color = RED;
  428.                 sibling->color = BLACK;
  429.                 RotateRight(x->parent);
  430.                 sibling = x->parent->left;
  431.             }
  432.             
  433.             if ((NULL == sibling->left || BLACK == sibling->left->color) && /
  434.                 (NULL == sibling->right || BLACK == sibling->right->color))
  435.             {
  436.                 sibling->color = RED;
  437.                 x = x->parent;
  438.             }
  439.             else 
  440.             {
  441.                 if ((NULL == sibling->left) || (BLACK == sibling->left->color))
  442.                 {
  443.                     sibling->color = RED;
  444.                     sibling->right->color = BLACK;
  445.                     RotateLeft(sibling);
  446.                     sibling = x->parent->left;
  447.                 }                       
  448.                 sibling->color = x->parent->color;
  449.                 x->parent->color = BLACK;   
  450.                 sibling->left->color = BLACK;
  451.                 RotateRight(x->parent); 
  452.                 break;
  453.             }
  454.             
  455.         }
  456.     }   
  457.     x->color = BLACK;   
  458. }
  459. //显示每个节点的键和值
  460. void RBTree::Display(RBTreeNode *x)
  461. {
  462.     cout << x->key << "--" << x->value << endl;
  463. }
  464. //中序遍历红黑树内部函数
  465. void RBTree::InOrder(RBTreeNode *y, void (RBTree::*callback)(RBTreeNode*))
  466. {
  467.     if (NULL == y)
  468.     {
  469.         return;
  470.     }
  471.     InOrder(y->left, callback);
  472.     Display(y);
  473.     InOrder(y->right, callback);
  474. }
  475. //中序遍历红黑树
  476. void RBTree::InOrder()
  477. {
  478.     InOrder(root, RBTree::Display);
  479. }

抱歉!评论已关闭.