• 数据结构--树--红黑树




    • R-B Tree简介

          R-B Tree,全称是Red-Black Tree,又称为“红黑树”,它一种特殊的二叉查找树。红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black)。

      红黑树的特性:
      (1)每个节点或者是黑色,或者是红色。
      (2)根节点是黑色。
      (3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
      (4)如果一个节点是红色的,则它的子节点必须是黑色的。
      (5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

      注意
      (01) 特性(3)中的叶子节点,是只为空(NIL或null)的节点。
      (02) 特性(5),确保没有一条路径会比其他路径长出俩倍。因而,红黑树是相对是接近平衡的二叉树。

      红黑树示意图如下:





    • 红黑树的时间复杂度

      红黑树的时间复杂度为: O(lgn)

      定理:一棵含有n个节点的红黑树的高度至多为2log(n+1).


    • 红黑树的基本操作(一) 左旋和右旋

      红黑树的基本操作是添加删除。在对红黑树进行添加或删除之后,都会用到旋转方法。为什么呢?道理很简单,添加或删除红黑树中的节点之后,红黑树就发生了变化,可能不满足红黑树的5条性质,也就不再是一颗红黑树了,而是一颗普通的树。而通过旋转,可以使这颗树重新成为红黑树。简单点说,旋转的目的是让树保持红黑树的特性。
      旋转包括两种:左旋右旋。下面分别对它们进行介绍。

      1. 左旋

      对x进行左旋,意味着"将x变成一个左节点"。

      左旋实例,进行测试



      2. 右旋

      对x进行左旋,意味着"将x变成一个左节点"。

      右旋实例




      3. 区分 左旋 和 右旋

      仔细观察上面"左旋"和"右旋"的示意图。我们能清晰的发现,它们是对称的。无论是左旋还是右旋,被旋转的树,在旋转前是二叉查找树,并且旋转之后仍然是一颗二叉查找树。




    • 红黑树的基本操作(二) 添加

      将一个节点插入到红黑树中,需要执行哪些步骤呢?首先,将红黑树当作一颗二叉查找树,将节点插入;然后,将节点着色为红色;最后,通过旋转和重新着色等方法来修正该树,使之重新成为一颗红黑树。详细描述如下:

      第一步: 将红黑树当作一颗二叉查找树,将节点插入。
             红黑树本身就是一颗二叉查找树,将节点插入后,该树仍然是一颗二叉查找树。也就意味着,树的键值仍然是有序的。此外,无论是左旋还是右旋,若旋转之前这棵树是二叉查找树,旋转之后它一定还是二叉查找树。这也就意味着,任何的旋转和重新着色操作,都不会改变它仍然是一颗二叉查找树的事实。
             好吧?那接下来,我们就来想方设法的旋转以及重新着色,使这颗树重新成为红黑树!

      第二步:将插入的节点着色为"红色"。
             为什么着色成红色,而不是黑色呢?为什么呢?在回答之前,我们需要重新温习一下红黑树的特性:
      (1) 每个节点或者是黑色,或者是红色。
      (2) 根节点是黑色。
      (3) 每个叶子节点是黑色。 [注意:这里叶子节点,是指为空的叶子节点!]
      (4) 如果一个节点是红色的,则它的子节点必须是黑色的。
      (5) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
             将插入的节点着色为红色,不会违背"特性(5)"!少违背一条特性,就意味着我们需要处理的情况越少。接下来,就要努力的让这棵树满足其它性质即可;满足了的话,它就又是一颗红黑树了。o(∩∩)o...哈哈

      第三步: 通过一系列的旋转或着色等操作,使之重新成为一颗红黑树。
             第二步中,将插入节点着色为"红色"之后,不会违背"特性(5)"。那它到底会违背哪些特性呢?
             对于"特性(1)",显然不会违背了。因为我们已经将它涂成红色了。
             对于"特性(2)",显然也不会违背。在第一步中,我们是将红黑树当作二叉查找树,然后执行的插入操作。而根据二叉查找数的特点,插入操作不会改变根节点。所以,根节点仍然是黑色。
             对于"特性(3)",显然不会违背了。这里的叶子节点是指的空叶子节点,插入非空节点并不会对它们造成影响。
             对于"特性(4)",是有可能违背的!
             那接下来,想办法使之"满足特性(4)",就可以将树重新构造成红黑树了。

      根据被插入节点的父节点的情况,可以将"当节点z被着色为红色节点,并插入二叉树"划分为三种情况来处理。
      ① 情况说明:被插入的节点是根节点。
          处理方法:直接把此节点涂为黑色。
      ② 情况说明:被插入的节点的父节点是黑色。
          处理方法:什么也不需要做。节点被插入后,仍然是红黑树。
      ③ 情况说明:被插入的节点的父节点是红色。
          处理方法:那么,该情况与红黑树的“特性(5)”相冲突。这种情况下,被插入节点是一定存在非空祖父节点的;进一步的讲,被插入节点也一定存在叔叔节点(即使叔叔节点为空,我们也视之为存在,空节点本身就是黑色节点)。理解这点之后,我们依据"叔叔节点的情况",将这种情况进一步划分为3种情况(Case)。

        现象说明 处理策略
      Case 1 当前节点的父节点是红色,且当前节点的祖父节点的另一个子节点(叔叔节点)也是红色。

      (01) 将“父节点”设为黑色。
      (02) 将“叔叔节点”设为黑色。
      (03) 将“祖父节点”设为“红色”。
      (04) 将“祖父节点”设为“当前节点”(红色节点);即,之后继续对“当前节点”进行操作。

      Case 2 当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的右孩子

      (01) 将“父节点”作为“新的当前节点”。
      (02) 以“新的当前节点”为支点进行左旋。

      Case 3 当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的左孩子

      (01) 将“父节点”设为“黑色”。
      (02) 将“祖父节点”设为“红色”。
      (03) 以“祖父节点”为支点进行右旋。

      上面三种情况(Case)处理问题的核心思路都是:将红色的节点移到根节点;然后,将根节点设为黑色。下面对它们详细进行介绍。

      1. (Case 1)叔叔是红色

      1.1 现象说明
      当前节点(即,被插入节点)的父节点是红色,且当前节点的祖父节点的另一个子节点(叔叔节点)也是红色。

      1.2 处理策略
      (01) 将“父节点”设为黑色。
      (02) 将“叔叔节点”设为黑色。
      (03) 将“祖父节点”设为“红色”。
      (04) 将“祖父节点”设为“当前节点”(红色节点);即,之后继续对“当前节点”进行操作。

          下面谈谈为什么要这样处理。(建议理解的时候,通过下面的图进行对比)
          “当前节点”和“父节点”都是红色,违背“特性(4)”。所以,将“父节点”设置“黑色”以解决这个问题。
          但是,将“父节点”由“红色”变成“黑色”之后,违背了“特性(5)”:因为,包含“父节点”的分支的黑色节点的总数增加了1。  解决这个问题的办法是:将“祖父节点”由“黑色”变成红色,同时,将“叔叔节点”由“红色”变成“黑色”。关于这里,说明几点:第一,为什么“祖父节点”之前是黑色?这个应该很容易想明白,因为在变换操作之前,该树是红黑树,“父节点”是红色,那么“祖父节点”一定是黑色。 第二,为什么将“祖父节点”由“黑色”变成红色,同时,将“叔叔节点”由“红色”变成“黑色”;能解决“包含‘父节点’的分支的黑色节点的总数增加了1”的问题。这个道理也很简单。“包含‘父节点’的分支的黑色节点的总数增加了1” 同时也意味着 “包含‘祖父节点’的分支的黑色节点的总数增加了1”,既然这样,我们通过将“祖父节点”由“黑色”变成“红色”以解决“包含‘祖父节点’的分支的黑色节点的总数增加了1”的问题; 但是,这样处理之后又会引起另一个问题“包含‘叔叔’节点的分支的黑色节点的总数减少了1”,现在我们已知“叔叔节点”是“红色”,将“叔叔节点”设为“黑色”就能解决这个问题。 所以,将“祖父节点”由“黑色”变成红色,同时,将“叔叔节点”由“红色”变成“黑色”;就解决了该问题。
          按照上面的步骤处理之后:当前节点、父节点、叔叔节点之间都不会违背红黑树特性,但祖父节点却不一定。若此时,祖父节点是根节点,直接将祖父节点设为“黑色”,那就完全解决这个问题了;若祖父节点不是根节点,那我们需要将“祖父节点”设为“新的当前节点”,接着对“新的当前节点”进行分析。

      1.3 示意图

      2. (Case 2)叔叔是黑色,且当前节点是右孩子

      2.1 现象说明
      当前节点(即,被插入节点)的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的右孩子

      2.2 处理策略
      (01) 将“父节点”作为“新的当前节点”。
      (02) 以“新的当前节点”为支点进行左旋。

            下面谈谈为什么要这样处理。(建议理解的时候,通过下面的图进行对比)
            首先,将“父节点”作为“新的当前节点”;接着,以“新的当前节点”为支点进行左旋。 为了便于理解,我们先说明第(02)步,再说明第(01)步;为了便于说明,我们设置“父节点”的代号为F(Father),“当前节点”的代号为S(Son)。
      为什么要“以F为支点进行左旋”呢?根据已知条件可知:S是F的右孩子。而之前我们说过,我们处理红黑树的核心思想:将红色的节点移到根节点;然后,将根节点设为黑色。既然是“将红色的节点移到根节点”,那就是说要不断的将破坏红黑树特性的红色节点上移(即向根方向移动)。 而S又是一个右孩子,因此,我们可以通过“左旋”来将S上移!
            按照上面的步骤(以F为支点进行左旋)处理之后:若S变成了根节点,那么直接将其设为“黑色”,就完全解决问题了;若S不是根节点,那我们需要执行步骤(01),即“将F设为‘新的当前节点’”。那为什么不继续以S为新的当前节点继续处理,而需要以F为新的当前节点来进行处理呢?这是因为“左旋”之后,F变成了S的“子节点”,即S变成了F的父节点;而我们处理问题的时候,需要从下至上(由叶到根)方向进行处理;也就是说,必须先解决“孩子”的问题,再解决“父亲”的问题;所以,我们执行步骤(01):将“父节点”作为“新的当前节点”。

      2.2 示意图

      3. (Case 3)叔叔是黑色,且当前节点是左孩子

      3.1 现象说明
      当前节点(即,被插入节点)的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的左孩子

      3.2 处理策略
      (01) 将“父节点”设为“黑色”。
      (02) 将“祖父节点”设为“红色”。
      (03) 以“祖父节点”为支点进行右旋。

            下面谈谈为什么要这样处理。(建议理解的时候,通过下面的图进行对比)
            为了便于说明,我们设置“当前节点”为S(Original Son),“兄弟节点”为B(Brother),“叔叔节点”为U(Uncle),“父节点”为F(Father),祖父节点为G(Grand-Father)。
            S和F都是红色,违背了红黑树的“特性(4)”,我们可以将F由“红色”变为“黑色”,就解决了“违背‘特性(4)’”的问题;但却引起了其它问题:违背特性(5),因为将F由红色改为黑色之后,所有经过F的分支的黑色节点的个数增加了1。那我们如何解决“所有经过F的分支的黑色节点的个数增加了1”的问题呢? 我们可以通过“将G由黑色变成红色”,同时“以G为支点进行右旋”来解决。

      2.3 示意图

      提示:上面的进行Case 3处理之后,再将节点"120"当作当前节点,就变成了Case 2的情况。



    • 红黑树的基本操作(三) 删除

      将红黑树内的某一个节点删除。需要执行的操作依次是:首先,将红黑树当作一颗二叉查找树,将该节点从二叉查找树中删除;然后,通过"旋转和重新着色"等一系列来修正该树,使之重新成为一棵红黑树。详细描述如下:

      第一步:将红黑树当作一颗二叉查找树,将节点删除。
             这和"删除常规二叉查找树中删除节点的方法是一样的"。分3种情况:
             ① 被删除节点没有儿子,即为叶节点。那么,直接将该节点删除就OK了。
             ② 被删除节点只有一个儿子。那么,直接删除该节点,并用该节点的唯一子节点顶替它的位置。
             ③ 被删除节点有两个儿子。那么,先找出它的后继节点;然后把“它的后继节点的内容”复制给“该节点的内容”;之后,删除“它的后继节点”。在这里,后继节点相当于替身,在将后继节点的内容复制给"被删除节点"之后,再将后继节点删除。这样就巧妙的将问题转换为"删除后继节点"的情况了,下面就考虑后继节点。 在"被删除节点"有两个非空子节点的情况下,它的后继节点不可能是双子非空。既然"的后继节点"不可能双子都非空,就意味着"该节点的后继节点"要么没有儿子,要么只有一个儿子。若没有儿子,则按"情况① "进行处理;若只有一个儿子,则按"情况② "进行处理。

      第二步:通过"旋转和重新着色"等一系列来修正该树,使之重新成为一棵红黑树。
             因为"第一步"中删除节点之后,可能会违背红黑树的特性。所以需要通过"旋转和重新着色"来修正该树,使之重新成为一棵红黑树。


      下面对删除函数进行分析。在分析之前,我们再次温习一下红黑树的几个特性:
      (1) 每个节点或者是黑色,或者是红色。
      (2) 根节点是黑色。
      (3) 每个叶子节点是黑色。 [注意:这里叶子节点,是指为空的叶子节点!]
      (4) 如果一个节点是红色的,则它的子节点必须是黑色的。
      (5) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。


            前面我们将"删除红黑树中的节点"大致分为两步,在第一步中"将红黑树当作一颗二叉查找树,将节点删除"后,可能违反"特性(2)、(4)、(5)"三个特性。第二步需要解决上面的三个问题,进而保持红黑树的全部特性。
            为了便于分析,我们假设"x包含一个额外的黑色"(x原本的颜色还存在),这样就不会违反"特性(5)"。为什么呢?
            通过RB-DELETE算法,我们知道:删除节点y之后,x占据了原来节点y的位置。 既然删除y(y是黑色),意味着减少一个黑色节点;那么,再在该位置上增加一个黑色即可。这样,当我们假设"x包含一个额外的黑色",就正好弥补了"删除y所丢失的黑色节点",也就不会违反"特性(5)"。 因此,假设"x包含一个额外的黑色"(x原本的颜色还存在),这样就不会违反"特性(5)"。
            现在,x不仅包含它原本的颜色属性,x还包含一个额外的黑色。即x的颜色属性是"红+黑"或"黑+黑",它违反了"特性(1)"。

            现在,我们面临的问题,由解决"违反了特性(2)、(4)、(5)三个特性"转换成了"解决违反特性(1)、(2)、(4)三个特性"。RB-DELETE-FIXUP需要做的就是通过算法恢复红黑树的特性(1)、(2)、(4)。RB-DELETE-FIXUP的思想是:将x所包含的额外的黑色不断沿树上移(向根方向移动),直到出现下面的姿态:
      a) x指向一个"红+黑"节点。此时,将x设为一个"黑"节点即可。
      b) x指向根。此时,将x设为一个"黑"节点即可。
      c) 非前面两种姿态。

      将上面的姿态,可以概括为3种情况。
      ① 情况说明:x是“红+黑”节点。
          处理方法:直接把x设为黑色,结束。此时红黑树性质全部恢复。
      ② 情况说明:x是“黑+黑”节点,且x是根。
          处理方法:什么都不做,结束。此时红黑树性质全部恢复。
      ③ 情况说明:x是“黑+黑”节点,且x不是根。
          处理方法:这种情况又可以划分为4种子情况。这4种子情况如下表所示:

        现象说明 处理策略
      Case 1 x是"黑+黑"节点,x的兄弟节点是红色。(此时x的父节点和x的兄弟节点的子节点都是黑节点)。

      (01) 将x的兄弟节点设为“黑色”。
      (02) 将x的父节点设为“红色”。
      (03) 对x的父节点进行左旋。
      (04) 左旋后,重新设置x的兄弟节点。

      Case 2 x是“黑+黑”节点,x的兄弟节点是黑色,x的兄弟节点的两个孩子都是黑色。

      (01) 将x的兄弟节点设为“红色”。
      (02) 设置“x的父节点”为“新的x节点”。

      Case 3 x是“黑+黑”节点,x的兄弟节点是黑色;x的兄弟节点的左孩子是红色,右孩子是黑色的。

      (01) 将x兄弟节点的左孩子设为“黑色”。
      (02) 将x兄弟节点设为“红色”。
      (03) 对x的兄弟节点进行右旋。
      (04) 右旋后,重新设置x的兄弟节点。

      Case 4 x是“黑+黑”节点,x的兄弟节点是黑色;x的兄弟节点的右孩子是红色的,x的兄弟节点的左孩子任意颜色。

      (01) 将x父节点颜色 赋值给 x的兄弟节点。
      (02) 将x父节点设为“黑色”。
      (03) 将x兄弟节点的右子节设为“黑色”。
      (04) 对x的父节点进行左旋。
      (05) 设置“x”为“根节点”。

      1. (Case 1)x是"黑+黑"节点,x的兄弟节点是红色

      1.1 现象说明
      x是"黑+黑"节点,x的兄弟节点是红色。(此时x的父节点和x的兄弟节点的子节点都是黑节点)。

      1.2 处理策略
      (01) 将x的兄弟节点设为“黑色”。
      (02) 将x的父节点设为“红色”。
      (03) 对x的父节点进行左旋。
      (04) 左旋后,重新设置x的兄弟节点。

            下面谈谈为什么要这样处理。(建议理解的时候,通过下面的图进行对比)
            这样做的目的是将“Case 1”转换为“Case 2”、“Case 3”或“Case 4”,从而进行进一步的处理。对x的父节点进行左旋;左旋后,为了保持红黑树特性,就需要在左旋前“将x的兄弟节点设为黑色”,同时“将x的父节点设为红色”;左旋后,由于x的兄弟节点发生了变化,需要更新x的兄弟节点,从而进行后续处理。

      1.3 示意图

      2. (Case 2) x是"黑+黑"节点,x的兄弟节点是黑色,x的兄弟节点的两个孩子都是黑色

      2.1 现象说明
      x是“黑+黑”节点,x的兄弟节点是黑色,x的兄弟节点的两个孩子都是黑色。

      2.2 处理策略
      (01) 将x的兄弟节点设为“红色”。
      (02) 设置“x的父节点”为“新的x节点”。

            下面谈谈为什么要这样处理。(建议理解的时候,通过下面的图进行对比)
            这个情况的处理思想:是将“x中多余的一个黑色属性上移(往根方向移动)”。 x是“黑+黑”节点,我们将x由“黑+黑”节点 变成 “黑”节点,多余的一个“黑”属性移到x的父节点中,即x的父节点多出了一个黑属性(若x的父节点原先是“黑”,则此时变成了“黑+黑”;若x的父节点原先时“红”,则此时变成了“红+黑”)。 此时,需要注意的是:所有经过x的分支中黑节点个数没变化;但是,所有经过x的兄弟节点的分支中黑色节点的个数增加了1(因为x的父节点多了一个黑色属性)!为了解决这个问题,我们需要将“所有经过x的兄弟节点的分支中黑色节点的个数减1”即可,那么就可以通过“将x的兄弟节点由黑色变成红色”来实现。
            经过上面的步骤(将x的兄弟节点设为红色),多余的一个颜色属性(黑色)已经跑到x的父节点中。我们需要将x的父节点设为“新的x节点”进行处理。若“新的x节点”是“黑+红”,直接将“新的x节点”设为黑色,即可完全解决该问题;若“新的x节点”是“黑+黑”,则需要对“新的x节点”进行进一步处理。

      2.3 示意图

      3. (Case 3)x是“黑+黑”节点,x的兄弟节点是黑色;x的兄弟节点的左孩子是红色,右孩子是黑色的

      3.1 现象说明
      x是“黑+黑”节点,x的兄弟节点是黑色;x的兄弟节点的左孩子是红色,右孩子是黑色的。

      3.2 处理策略
      (01) 将x兄弟节点的左孩子设为“黑色”。
      (02) 将x兄弟节点设为“红色”。
      (03) 对x的兄弟节点进行右旋。
      (04) 右旋后,重新设置x的兄弟节点。

             下面谈谈为什么要这样处理。(建议理解的时候,通过下面的图进行对比)
             我们处理“Case 3”的目的是为了将“Case 3”进行转换,转换成“Case 4”,从而进行进一步的处理。转换的方式是对x的兄弟节点进行右旋;为了保证右旋后,它仍然是红黑树,就需要在右旋前“将x的兄弟节点的左孩子设为黑色”,同时“将x的兄弟节点设为红色”;右旋后,由于x的兄弟节点发生了变化,需要更新x的兄弟节点,从而进行后续处理。

      3.3 示意图

      4. (Case 4)x是“黑+黑”节点,x的兄弟节点是黑色;x的兄弟节点的右孩子是红色的,x的兄弟节点的左孩子任意颜色

      4.1 现象说明
      x是“黑+黑”节点,x的兄弟节点是黑色;x的兄弟节点的右孩子是红色的,x的兄弟节点的左孩子任意颜色。

      4.2 处理策略
      (01) 将x父节点颜色 赋值给 x的兄弟节点。
      (02) 将x父节点设为“黑色”。
      (03) 将x兄弟节点的右子节设为“黑色”。
      (04) 对x的父节点进行左旋。
      (05) 设置“x”为“根节点”。

            下面谈谈为什么要这样处理。(建议理解的时候,通过下面的图进行对比)
            我们处理“Case 4”的目的是:去掉x中额外的黑色,将x变成单独的黑色。处理的方式是“:进行颜色修改,然后对x的父节点进行左旋。下面,我们来分析是如何实现的。
            为了便于说明,我们设置“当前节点”为S(Original Son),“兄弟节点”为B(Brother),“兄弟节点的左孩子”为BLS(Brother's Left Son),“兄弟节点的右孩子”为BRS(Brother's Right Son),“父节点”为F(Father)。
            我们要对F进行左旋。但在左旋前,我们需要调换F和B的颜色,并设置BRS为黑色。为什么需要这里处理呢?因为左旋后,F和BLS是父子关系,而我们已知BL是红色,如果F是红色,则违背了“特性(4)”;为了解决这一问题,我们将“F设置为黑色”。 但是,F设置为黑色之后,为了保证满足“特性(5)”,即为了保证左旋之后:
            第一,“同时经过根节点和S的分支的黑色节点个数不变”。
                   若满足“第一”,只需要S丢弃它多余的颜色即可。因为S的颜色是“黑+黑”,而左旋后“同时经过根节点和S的分支的黑色节点个数”增加了1;现在,只需将S由“黑+黑”变成单独的“黑”节点,即可满足“第一”。
            第二,“同时经过根节点和BLS的分支的黑色节点数不变”。
                   若满足“第二”,只需要将“F的原始颜色”赋值给B即可。之前,我们已经将“F设置为黑色”(即,将B的颜色"黑色",赋值给了F)。至此,我们算是调换了F和B的颜色。
            第三,“同时经过根节点和BRS的分支的黑色节点数不变”。
                   在“第二”已经满足的情况下,若要满足“第三”,只需要将BRS设置为“黑色”即可。
      经过,上面的处理之后。红黑树的特性全部得到的满足!接着,我们将x设为根节点,就可以跳出while循环(参考伪代码);即完成了全部处理。

      至此,我们就完成了Case 4的处理。理解Case 4的核心,是了解如何“去掉当前节点额外的黑色”。

      4.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




    • caokaoboke:http://www.cnblogs.com/skywang12345/p/3624291.html.
  • 相关阅读:
    W3C代码标准规范
    我们为什么要遵循W3C标准规范
    WEB标准:标准定义、好处、名词解释、常用术语、命名习惯、浏览器兼容、代码书写规范
    ThinkPHP框架下,给jq动态添加的标签添加点击事件移除标签
    ThinkPHP框架下,jq实现在div中添加标签并且div的大小会随之变化
    Windows下spark1.6.0本地环境搭建
    Mysql中使用SQL计算两个日期时间差值
    jquery正则表达式验证:手机号码
    jquery正则表达式验证:验证邮箱格式是否正确
    jquery正则表达式验证:整数12位,小数钱12位小数点后2位
  • 原文地址:https://www.cnblogs.com/Kobe10/p/5617400.html
Copyright © 2020-2023  润新知