红黑树

原文出自:http://dsqiu.iteye.com/blog/1706340

红黑树(Red-Black Tree)

红黑树定义

红黑树是每个节点都带有颜色属性的二叉查找树,颜色为红色黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:

    性质1. 节点是红色或黑色。

    性质2. 根是黑色。

    性质3. 所有叶子都是黑色(叶子是NIL节点)。

    性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)

    性质5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。

An example of a red-black tree

 

下面先给出红黑树的抽象数据类型

 

C代码   收藏代码
  1. #ifndef RBT_H  
  2. #define RBT_H  
  3.   
  4. typedef enum {  
  5.     RBT_STATUS_OK,  
  6.     RBT_STATUS_MEM_EXHAUSTED,  
  7.     RBT_STATUS_DUPLICATE_KEY,  
  8.     RBT_STATUS_KEY_NOT_FOUND  
  9. } RbtStatus;  
  10.   
  11. typedef void *RbtIterator;  
  12. typedef void *RbtHandle;  
  13.   
  14. RbtHandle rbtNew(int(*compare)(void *a, void *b));  
  15. // create red-black tree  
  16. // parameters:  
  17. //     compare  pointer to function that compares keys  
  18. //              return 0   if a == b  
  19. //              return < 0 if a < b  
  20. //              return > 0 if a > b  
  21. // returns:  
  22. //     handle   use handle in calls to rbt functions  
  23.   
  24.   
  25. void rbtDelete(RbtHandle h);  
  26. // destroy red-black tree  
  27.   
  28. RbtStatus rbtInsert(RbtHandle h, void *key, void *value);  
  29. // insert key/value pair  
  30.   
  31. RbtStatus rbtErase(RbtHandle h, RbtIterator i);  
  32. // delete node in tree associated with iterator  
  33. // this function does not free the key/value pointers  
  34.   
  35. RbtIterator rbtNext(RbtHandle h, RbtIterator i);  
  36. // return ++i  
  37.   
  38. RbtIterator rbtBegin(RbtHandle h);  
  39. // return pointer to first node  
  40.   
  41. RbtIterator rbtEnd(RbtHandle h);  
  42. // return pointer to one past last node  
  43.   
  44. void rbtKeyValue(RbtHandle h, RbtIterator i, void **key, void **value);  
  45. // returns key/value pair associated with iterator  
  46.   
  47. RbtIterator rbtFind(RbtHandle h, void *key);  
  48. // returns iterator associated with key  
  49.   
  50. #endif  

 

红黑树平衡化旋转

红黑树的旋转操作没有AVL树那么复杂,这里的旋转也不区分结点的颜色,纯粹是旋转移动结点的位置,即只有两种操作——左旋和右旋。

1.左旋

红黑树的介绍和实现[原创] - saturnman - 一路

 

C代码   收藏代码
  1. static void rotateLeft(RbtType *rbt, NodeType *x) {  
  2.   
  3.     // rotate node x to left  
  4.   
  5.     NodeType *y = x->right;  
  6.   
  7.     // establish x->right link  
  8.     x->right = y->left;  
  9.     if (y->left != SENTINEL) y->left->parent = x;  
  10.   
  11.     // establish y->parent link  
  12.     if (y != SENTINEL) y->parent = x->parent;  
  13.     if (x->parent) {  
  14.         if (x == x->parent->left)  
  15.             x->parent->left = y;  
  16.         else  
  17.             x->parent->right = y;  
  18.     } else {  
  19.         rbt->root = y;  
  20.     }  
  21.   
  22.     // link x and y  
  23.     y->left = x;  
  24.     if (x != SENTINEL) x->parent = y;  
  25. }  
 

 

2.右旋

  红黑树的介绍和实现[原创] - saturnman - 一路

 

C代码   收藏代码
  1. static void rotateRight(RbtType *rbt, NodeType *x) {  
  2.   
  3.     // rotate node x to right  
  4.   
  5.     NodeType *y = x->left;  
  6.   
  7.     // establish x->left link  
  8.     x->left = y->right;  
  9.     if (y->right != SENTINEL) y->right->parent = x;  
  10.   
  11.     // establish y->parent link  
  12.     if (y != SENTINEL) y->parent = x->parent;  
  13.     if (x->parent) {  
  14.         if (x == x->parent->right)  
  15.             x->parent->right = y;  
  16.         else  
  17.             x->parent->left = y;  
  18.     } else {  
  19.         rbt->root = y;  
  20.     }  
  21.   
  22.     // link x and y  
  23.     y->right = x;  
  24.     if (x != SENTINEL) x->parent = y;  
  25. }  

 

 红黑树的插入和删除

 

1. 插入操作

    我们总是插入红色的节点,因为这样就可以在插入过程中尽量避免产生对树的调整,我们新插入一个节点后可能使原树的哪些性质改变呢。由于我们是按二叉树的方式插入,因此原树的搜索性质不会改变。如果插入的节点是根节点,性质2会被破坏,如果插入的节点的父节点是红色,则会破坏性质4,因此总的来说,插入一个红色节点只会破坏到性质2或是性质4,我们的恢复树性质的策略很简单,其一就是保持一定的性质不变,之后把出现违背红黑树性质地方向上移,如果能移到根节点,那么很容易就可以通过直接修改根节点来恢复红黑树应满足的性质。其二就是穷举所有的可能性,之后把能归于同一类方法处理的归为同一类,不能直接处理的化归到其它可以直接处理的情况,能直接处理的就直接处理。

下面看看一共有几种情况,

情况1:插入的是根节点(原树是空树)

此情况只会违反性质2。

解法:直接把此节点涂为黑色

情况2:插入的节点的的父节点是黑色

此时不会违反性质2也不会违反性质4,红黑树没有被破坏。

解法:什么都不做

情况3:当前节点的父节点是红色且祖父节点的另一个子节点(叔叔节点)是红色(此时父节点的父节点一定存在,否则插入前就已不是红黑树,此时又分为父节点是祖父节点的左子或者右子,对于对称性,只要解开一个方向就可以了,我们只考虑父节点为祖父左子的情况)。此时还可分为当前节点是其父节点的左子还是右子,但是这两种情况的处理方式是一样的,我们将其归为同一类。

解法:将当前节点的父节点和叔叔节点涂黑,祖父结点涂红,把当前结点指向祖父节点,从新的当前节点重新开始算法。

下面是算法导论一书中的图,稍做修改(N代表当前节点,P代表父节点,G代表祖父节点,U代表叔叔节点,以下各图如果相同字母则代表同一意思,不再详述)。

变换前

红黑树的介绍和实现[原创] - saturnman - 一路

变换后

红黑树的介绍和实现[原创] - saturnman - 一路

情况4:当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的右子

解法:当前节点的父节点做为新的当前节点,以新当前节点为支点左旋。

如下图所示

变换前

 

红黑树的介绍和实现[原创] - saturnman - 一路

 

变换后

红黑树的介绍和实现[原创] - saturnman - 一路

情况5:当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的左子

解法:父节点变为黑色,祖父节点变为红色,在祖父节点为支点右旋

如下图所示

变换前

红黑树的介绍和实现[原创] - saturnman - 一路

变换后

红黑树的介绍和实现[原创] - saturnman - 一路

在上面的插入算法中,所有递归都是尾递归,可以改写为循环,其中以当前节点的父节点是否为红色是十分方便的。

2.删除操作

    我们删除的节点的方法与常规二叉搜索树中删除节点的方法是一样的,如果被删除的节点不是有双非空子女,则直接删除这个节点,用它的唯一子节点顶替它的位置,如果它的子节点分是空节点,那就用空节点顶替它的位置,如果它的双子全为非空,我们就把它的直接后继节点内容复制到它的位置,之后以同样的方式删除它的后继节点,它的后继节点不可能是双子非空,因此此传递过程最多只进行一次。在册除节点后,原红黑树的性质可能被改变,如果删除的是红色节点,那么原红黑树的性质依旧保持,此时不用做修正操作,如果删除的节点是黑色节点,原红黑树的性质可能会被改变,我们要对其做修正操作。那么哪些树的性质会发生变化呢,如果删除节点不是树唯一节点,那么删除节点的那一个支的到各叶节点的黑色节点数会发生变化,此时性质5被破坏。如果被删节点的唯物主唯一非空子节点是红色,而被删节点的父节点也是红色,那么性质4被破坏。如果被删节点是根节点,而它的唯一非空子节点是红色,则删除后新根节点将变成红色,违背性质2。现在情况看起来有些复杂,这里面我们用一个分析技巧,这引技巧是从《算法导论》一书中学来的。我们从被删节点后来顶替它的那个节点开始调整,并认为它有额外的一重黑色。这里额外一重黑色是什么意思呢,我们不是把红黑树的节点加上除红与黑的另一种颜色,这里只是一种假设,我们认为我们当前指向它,因此空有额外一种黑色,可以认为它的黑色是从它的父节点被删除后继承给它的,它现在可以容纳两种颜色,如果它原来是红色,那么现在是红+黑,如果原来是黑色,那么它现在的颜色是黑+黑。有了这重额外的黑色,原红黑树性质5就能保持不变。现在只要花时是恢复其它性质就可以了,做法还是尽量向根移动和穷举所有可能性。

情况1:当前节点是红+黑色

    解法,直接把当前节点染成黑色,结束。

此时红黑树性质全部恢复。

情况2:当前节点是黑+黑且是根节点

    解法:什么都不做,结束

情况3:当前节点是黑+黑且兄弟节点为红色(此时父节点和兄弟节点的子节点分为黑)。

    解法:把父节点染成红色,把兄弟结点染成黑色,之后重新进入算法(我们只讨论当前节点是其父节点左孩子时的情况)。此变换后原红黑树性质5不变,而把问题转化为兄弟节点为黑色的情况。

变换前

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

 

 

变换后

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

 情况4:当前节点是黑加黑且兄弟是黑色且兄弟节点的两个子节点全为黑色

    解法:把当前节点和兄弟节点中抽取一重黑色追加到父节点上,把父节点当成新的当前节点,重新进入算法。(此变换后性质5不变)

变换前

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

 

 

变换后

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

情况5:当前节点颜色是黑+黑,兄弟节点是黑色,兄弟的左子是红色,右子是黑色。

 

解法:把兄弟结点染红,兄弟左子节点染黑,之后再在兄弟节点为支点解右旋,之后重新进入算法。此是把当前的情况转化为情况6,而性质5得以保持。

变换前

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

 变换后

 

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

 情况6:当前节点颜色是黑-黑,它的兄弟节点是黑色,但是兄弟节点的右子是红色,兄弟节点左子的颜色任意。

 

解法:把兄弟节点染成当前节点父节点的颜色,把当前节点父节点染成黑色,兄弟节点右子染成黑色,之后以当前节点的父节点为支点进行左旋,此时算法结束,红黑树所有性质调整正确。

 

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

 变换后

 

 

红黑树的介绍和实现(一)[原创] - saturnman - 一路

 

红黑树的高度分析

包含n个内部节点的红黑树的高度是 O(log(n))。

定义:

  • h(v) = 以节点v为根的子树的高度。
  • bh(v) = 从v到子树中任何叶子的黑色节点的数目(如果v是黑色则不计数它)(也叫做黑色高度)。

引理: 以节点v为根的子树有至少2^{bh(v)}-1个内部节点。

引理的证明(通过归纳高度):

基础: h(v) = 0

如果v的高度是零则它必定是 nil,因此 bh(v) = 0。所以:

2^{bh(v)}-1 = 2^{0}-1 = 1-1 = 0

归纳假设: h(v) = k 的v有 2^{bh(v)-1}-1 个内部节点暗示了 h(v') = k+1 的 v'2^{bh(v')}-1 个内部节点。

因为 v' 有 h(v') > 0 所以它是个内部节点。同样的它有黑色高度要么是 bh(v') 要么是 bh(v')-1 (依据v'是红色还是黑色)的两个儿子。通过归纳假设每个儿子都有至少 2^{bh(v')-1}-1 个内部接点,所以 v' 有:

2^{bh(v')-1}-1 + 2^{bh(v')-1}-1 + 1 = 2^{bh(v')}-1

个内部节点。

使用这个引理我们现在可以展示出树的高度是对数性的。因为在从根到叶子的任何路径上至少有一半的节点是黑色(根据红黑树属性4),根的黑色高度至少是h(root)/2。通过引理我们得到:

n \geq 2^{​{h(root) \over 2}} - 1 \leftrightarrow \; \log{(n+1)} \geq {h(root) \over 2} \leftrightarrow \; h(root) \leq 2\log{(n+1)}

因此根的高度是O(log(n))。

 

下面附上完整的实现代码

 

 

C代码   收藏代码
  1. // red-black tree  
  2.   
  3. #include <stdio.h>  
  4. #include <stdlib.h>  
  5. #include <string.h>  
  6. #include <stdarg.h>  
  7.   
  8. //  
  9. // supplied by user //  
  10. //  
  11.   
  12. typedef int KeyType;            // type of key  
  13.   
  14. typedef struct {                // value related to key  
  15.     int stuff;  
  16. } ValType;  
  17.   
  18. // how to compare keys  
  19. #define compLT(a,b) (a < b)  
  20. #define compEQ(a,b) (a == b)  
  21.   
  22. /  
  23. // implementation independent code //  
  24. /  
  25.   
  26. typedef enum {  
  27.     RBT_STATUS_OK,  
  28.     RBT_STATUS_MEM_EXHAUSTED,  
  29.     RBT_STATUS_DUPLICATE_KEY,  
  30.     RBT_STATUS_KEY_NOT_FOUND  
  31. } RbtStatus;  
  32.   
  33. typedef enum { BLACK, RED } nodeColor;  
  34.   
  35. typedef struct NodeTag {  
  36.     struct NodeTag *left;       // left child  
  37.     struct NodeTag *right;      // right child  
  38.     struct NodeTag *parent;     // parent  
  39.     nodeColor color;            // node color (BLACK, RED)  
  40.     KeyType key;                // key used for searching  
  41.     ValType val;                // data related to key  
  42. } NodeType;  
  43.   
  44. #define SENTINEL &sentinel      // all leafs are sentinels  
  45. static NodeType sentinel = { SENTINEL, SENTINEL, 0, BLACK, 0};  
  46.   
  47. static NodeType *root = SENTINEL; // root of red-black tree  
  48.   
  49. static void rotateLeft(NodeType *x) {  
  50.   
  51.     // rotate node x to left  
  52.   
  53.     NodeType *y = x->right;  
  54.   
  55.     // establish x->right link  
  56.     x->right = y->left;  
  57.     if (y->left != SENTINEL) y->left->parent = x;  
  58.   
  59.     // establish y->parent link  
  60.     if (y != SENTINEL) y->parent = x->parent;  
  61.     if (x->parent) {  
  62.         if (x == x->parent->left)  
  63.             x->parent->left = y;  
  64.         else  
  65.             x->parent->right = y;  
  66.     } else {  
  67.         root = y;  
  68.     }  
  69.   
  70.     // link x and y  
  71.     y->left = x;  
  72.     if (x != SENTINEL) x->parent = y;  
  73. }  
  74.   
  75. static void rotateRight(NodeType *x) {  
  76.   
  77.     // rotate node x to right  
  78.   
  79.     NodeType *y = x->left;  
  80.   
  81.     // establish x->left link  
  82.     x->left = y->right;  
  83.     if (y->right != SENTINEL) y->right->parent = x;  
  84.   
  85.     // establish y->parent link  
  86.     if (y != SENTINEL) y->parent = x->parent;  
  87.     if (x->parent) {  
  88.         if (x == x->parent->right)  
  89.             x->parent->right = y;  
  90.         else  
  91.             x->parent->left = y;  
  92.     } else {  
  93.         root = y;  
  94.     }  
  95.   
  96.     // link x and y  
  97.     y->right = x;  
  98.     if (x != SENTINEL) x->parent = y;  
  99. }  
  100.   
  101. static void insertFixup(NodeType *x) {  
  102.   
  103.     // maintain red-black tree balance  
  104.     // after inserting node x  
  105.   
  106.     // check red-black properties  
  107.     while (x != root && x->parent->color == RED) {  
  108.         // we have a violation  
  109.         if (x->parent == x->parent->parent->left) {  
  110.             NodeType *y = x->parent->parent->right;  
  111.             if (y->color == RED) {  
  112.   
  113.                 // uncle is RED  
  114.                 x->parent->color = BLACK;  
  115.                 y->color = BLACK;  
  116.                 x->parent->parent->color = RED;  
  117.                 x = x->parent->parent;  
  118.             } else {  
  119.   
  120.                 // uncle is BLACK  
  121.                 if (x == x->parent->right) {  
  122.                     // make x a left child  
  123.                     x = x->parent;  
  124.                     rotateLeft(x);  
  125.                 }  
  126.   
  127.                 // recolor and rotate  
  128.                 x->parent->color = BLACK;  
  129.                 x->parent->parent->color = RED;  
  130.                 rotateRight(x->parent->parent);  
  131.             }  
  132.         } else {  
  133.   
  134.             // mirror image of above code  
  135.             NodeType *y = x->parent->parent->left;  
  136.             if (y->color == RED) {  
  137.   
  138.                 // uncle is RED  
  139.                 x->parent->color = BLACK;  
  140.                 y->color = BLACK;  
  141.                 x->parent->parent->color = RED;  
  142.                 x = x->parent->parent;  
  143.             } else {  
  144.   
  145.                 // uncle is BLACK  
  146.                 if (x == x->parent->left) {  
  147.                     x = x->parent;  
  148.                     rotateRight(x);  
  149.                 }  
  150.                 x->parent->color = BLACK;  
  151.                 x->parent->parent->color = RED;  
  152.                 rotateLeft(x->parent->parent);  
  153.             }  
  154.         }  
  155.     }  
  156.     root->color = BLACK;  
  157. }  
  158.   
  159. // insert new node (no duplicates allowed)  
  160. RbtStatus rbtInsert(KeyType key, ValType val) {  
  161.     NodeType *current, *parent, *x;  
  162.   
  163.     // allocate node for data and insert in tree  
  164.   
  165.     // find future parent  
  166.     current = root;  
  167.     parent = 0;  
  168.     while (current != SENTINEL) {  
  169.         if (compEQ(key, current->key))   
  170.             return RBT_STATUS_DUPLICATE_KEY;  
  171.         parent = current;  
  172.         current = compLT(key, current->key) ?  
  173.             current->left : current->right;  
  174.     }  
  175.   
  176.     // setup new node  
  177.     if ((x = malloc (sizeof(*x))) == 0)  
  178.         return RBT_STATUS_MEM_EXHAUSTED;  
  179.     x->parent = parent;  
  180.     x->left = SENTINEL;  
  181.     x->right = SENTINEL;  
  182.     x->color = RED;  
  183.     x->key = key;  
  184.     x->val = val;  
  185.   
  186.     // insert node in tree  
  187.     if(parent) {  
  188.         if(compLT(key, parent->key))  
  189.             parent->left = x;  
  190.         else  
  191.             parent->right = x;  
  192.     } else {  
  193.         root = x;  
  194.     }  
  195.   
  196.     insertFixup(x);  
  197.   
  198.     return RBT_STATUS_OK;  
  199. }  
  200.   
  201. static void deleteFixup(NodeType *x) {  
  202.   
  203.     // maintain red-black tree balance  
  204.     // after deleting node x  
  205.   
  206.     while (x != root && x->color == BLACK) {  
  207.         if (x == x->parent->left) {  
  208.             NodeType *w = x->parent->right;  
  209.             if (w->color == RED) {  
  210.                 w->color = BLACK;  
  211.                 x->parent->color = RED;  
  212.                 rotateLeft (x->parent);  
  213.                 w = x->parent->right;  
  214.             }  
  215.             if (w->left->color == BLACK && w->right->color == BLACK) {  
  216.                 w->color = RED;  
  217.                 x = x->parent;  
  218.             } else {  
  219.                 if (w->right->color == BLACK) {  
  220.                     w->left->color = BLACK;  
  221.                     w->color = RED;  
  222.                     rotateRight (w);  
  223.                     w = x->parent->right;  
  224.                 }  
  225.                 w->color = x->parent->color;  
  226.                 x->parent->color = BLACK;  
  227.                 w->right->color = BLACK;  
  228.                 rotateLeft (x->parent);  
  229.                 x = root;  
  230.             }  
  231.         } else {  
  232.             NodeType *w = x->parent->left;  
  233.             if (w->color == RED) {  
  234.                 w->color = BLACK;  
  235.                 x->parent->color = RED;  
  236.                 rotateRight (x->parent);  
  237.                 w = x->parent->left;  
  238.             }  
  239.             if (w->right->color == BLACK && w->left->color == BLACK) {  
  240.                 w->color = RED;  
  241.                 x = x->parent;  
  242.             } else {  
  243.                 if (w->left->color == BLACK) {  
  244.                     w->right->color = BLACK;  
  245.                     w->color = RED;  
  246.                     rotateLeft (w);  
  247.                     w = x->parent->left;  
  248.                 }  
  249.                 w->color = x->parent->color;  
  250.                 x->parent->color = BLACK;  
  251.                 w->left->color = BLACK;  
  252.                 rotateRight (x->parent);  
  253.                 x = root;  
  254.             }  
  255.         }  
  256.     }  
  257.     x->color = BLACK;  
  258. }  
  259.   
  260. // delete node  
  261. RbtStatus rbtErase(NodeType * z) {  
  262.     NodeType *x, *y;  
  263.   
  264.     if (z->left == SENTINEL || z->right == SENTINEL) {  
  265.         // y has a SENTINEL node as a child  
  266.         y = z;  
  267.     } else {  
  268.         // find tree successor with a SENTINEL node as a child  
  269.         y = z->right;  
  270.         while (y->left != SENTINEL) y = y->left;  
  271.     }  
  272.   
  273.     // x is y's only child  
  274.     if (y->left != SENTINEL)  
  275.         x = y->left;  
  276.     else  
  277.         x = y->right;  
  278.   
  279.     // remove y from the parent chain  
  280.     x->parent = y->parent;  
  281.     if (y->parent)  
  282.         if (y == y->parent->left)  
  283.             y->parent->left = x;  
  284.         else  
  285.             y->parent->right = x;  
  286.     else  
  287.         root = x;  
  288.   
  289.     if (y != z) {  
  290.         z->key = y->key;  
  291.         z->val = y->val;  
  292.     }  
  293.   
  294.   
  295.     if (y->color == BLACK)  
  296.         deleteFixup (x);  
  297.   
  298.     free (y);  
  299.   
  300.     return RBT_STATUS_OK;  
  301. }  
  302.   
  303. // find key  
  304. NodeType *rbtFind(KeyType key) {  
  305.     NodeType *current;  
  306.     current = root;  
  307.     while(current != SENTINEL) {  
  308.         if(compEQ(key, current->key)) {  
  309.             return current;  
  310.         } else {  
  311.             current = compLT (key, current->key) ?  
  312.                 current->left : current->right;  
  313.         }  
  314.     }  
  315.     return NULL;  
  316. }  
  317.   
  318. // in-order walk of tree  
  319. void rbtInorder(NodeType *p, void (callback)(NodeType *)) {  
  320.     if (p == SENTINEL) return;  
  321.     rbtInorder(p->left, callback);  
  322.     callback(p);  
  323.     rbtInorder(p->right, callback);  
  324. }  
  325.   
  326. // delete nodes depth-first  
  327. void rbtDelete(NodeType *p) {  
  328.     if (p == SENTINEL) return;  
  329.     rbtDelete(p->left);  
  330.     rbtDelete(p->right);  
  331.     free(p);  
  332. }  
  333.   
  334. void displayNode(NodeType *p) {  
  335.     printf("%d %d\n", p->key, p->val.stuff);  
  336. }  
  337.   
  338. int main(int argc, char **argv) {  
  339.     int maxnum, ct;  
  340.     KeyType key;  
  341.     RbtStatus status;  
  342.   
  343.     // command-line:  
  344.     //  
  345.     //   rbt 2000  
  346.     //      process 2000 records  
  347.   
  348.     NodeType *p;  
  349.   
  350.     maxnum = atoi(argv[1]);  
  351.   
  352.     printf("maxnum = %d\n", maxnum);  
  353.     for (ct = maxnum; ct; ct--) {  
  354.         key = rand() % 90 + 1;  
  355.         if ((p = rbtFind(key)) != NULL) {  
  356.             if (p->val.stuff != 10*key) printf("fail val\n");  
  357.             status = rbtErase(p);  
  358.             if (status) printf("fail: status = %d\n", status);  
  359.         } else {  
  360.             ValType val;  
  361.             val.stuff = 10*key;  
  362.             status = rbtInsert(key, val);  
  363.             if (status) printf("fail: status = %d\n", status);  
  364.         }  
  365.     }  
  366.   
  367.     // output nodes in order  
  368.     rbtInorder(root, displayNode);  
  369.   
  370.     rbtDelete(root);  
  371.   
  372.     return 0;  
  373. }  
 

 

 

 

参考:

Implementation in C: http://epaperpress.com/sortsearch/txt/rbt.txt 

②维基百科: http://zh.wikipedia.org/zh/%E7%BA%A2%E9%BB%91%E6%A0%91

http://epaperpress.com/sortsearch/rbt.html

saturnma http://saturnman.blog.163.com/blog/static/5576112010969420383/

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值