java提高篇(四)红黑树之插入节点

来源:互联网 发布:淘宝买家退货发空包裹 编辑:程序博客网 时间:2024/05/22 15:13

关于红黑树的帖子不可谓不多。一开始我看的是july的帖子(链接:http://blog.csdn.NET/v_JULY_v/article/details/6105630),但是删除的时候他这系列说的不是很明白。也可以看维基百科上对于红黑树的说明,说的很清楚,但是全是英文的。。。


 这里主要讲讲我自己的理解,以我自己学习红黑树的经历来说的。


红黑树就是查找二叉树的一种,因为一般查找二叉树有可能退化成一条单链表。比如在你插入的节点的key是排好序的的时候有可能就会成为一条链表。所以就有了红黑树。使得不会退化成链表。

说到红黑树,就不得不说他的五大特点,这也是红黑树得以保持平衡的关键。

  1. 每个结点要么是红的要么是黑的。  
  2. 根结点是黑的。  
  3. 每个叶结点(叶结点即指树尾端NIL指针或NULL结点)都是黑的。  
  4. 如果一个结点是红的,那么它的两个儿子都是黑的。  
  5.  对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点。

我觉得1,2,3,4都很好理解,主要是5,这个可以看下面这个图。

从图上可以明确看出,从根节点13到每个叶子节点(NIL)的所有路径上都只有3个黑色的黑色节点,比如 13(黑)->8(红)->1(黑)->NILL黑)。


那么现在目标很明确。我要构造这样的一颗二叉树。分为下面的几个步骤:


一、先进行二叉查找树的插入操作。 

二叉查找树的插入很简单,先把要插入的节点的key与根进行比较,小则和根的左孩子做比较,大则跟右孩子作比较,直到找到叶子节点。值得注意,这样的插入操作,新插入的节点必定是原来叶子节点的位置。比如在上面的树种插入节点21,则会是下面的情况,暂且不考虑节点21的颜色该是红还是黑:


二、新插入的节点可能破坏了红黑树的平衡,所以进行平衡调整。

现在按照二叉查找树的插入方式插入了节点21,那么这个21该是什么颜色呢?

1、黑色,如果是黑色,那么不管原来的红黑树是什么样的,这样一定会破坏平衡,因为原来的树是平衡的,现在在这一条路径上多了一个黑色,必然违反了性质5(不记得的时候多看几遍性质,并理解是最好的)。
2、红色,如果新插入的点是红色的,那么也有可能会破坏平衡,主要可能是违反了性质4,比如上图中,新插入的点21的父节点22为红色。但是却有一种特殊情况,比如上图中,如果我插入一个key=0的节点。把0这个节点置为红色,并不会影响原来树的平衡,因为0的父节点是黑色。如下图:

好歹也有不需要调整的情况,所以还是选择把新插入的节点颜色置为红色


如果新插入的点是红色,那么就会有可能破坏平衡,像上面的新节点21 。这个时候我们把,21的颜色置为红色。则他的父亲也是红色,违反性质4,需要调整,怎么调整呢?现在就要看新插入的点的叔叔节点了。上面的节点27 。

因为21的叔叔27是红色的。所以要保持平衡,可以把25设置成红色,22,27分别设置成黑色,是不是也平衡了呢?如下图:


明显,单看以25为根的子树,是平衡了。但是带来了新的问题。17是红色的。孩子25也是红色的。还是违反了我们的性质4。所以我们还得再看25 。

这个时候还是同样的问题。25的父亲,叔叔都是红色的。重复上面的操作, 得到下面的树。

显然整棵树都平衡了。但是还有有问题。根节点颜色成了红色,这个好办,直接设置根节点颜色为黑色即可。于是整棵树平衡。并且没有违反红黑树的五大性质。如下图:

以上是插入的点的叔叔是红色的。但是如果叔叔是黑色的呢??

比如我需要在最原始的树上插入一个key=7的点。经过二叉查找树的插入操作之后,如下图


明显插入的节点7已经破坏平衡,并且父亲是红色,叔叔是NIL(黑色),这个时候我们又该怎么办呢?

这个时候假设我们能把6放到1的位置,1变成6的左孩子,并且交换1和6的颜色,那么是不是平衡了呢?如下图:

是不是很神奇呢?其实这个操作的名字叫做树的旋转。注意:设置颜色不是旋转的一部分。上面采用的就是树的左旋,以1作为旋转点(需要旋转的子树的根节点)。下面来看一种右旋。

这是插入7的情况,那假如我要插入的是5呢?执行二叉查找树树的操作后是这样的:


这个时候我们要变通一下,把这张情况转换成上一种情况,也就是插入7的情况,是不是我们就会了。。但是怎么转换呢?还是树的旋转,旋转成下图。

这就是树的右旋,旋转6这颗子树。然后再像上面插入节点7一样,先交换1和5的颜色,左旋子树1 ,最后就平衡了。

执行这个操作的情况,我觉得按我的理解,很形象生动的就是需要自己,父亲,祖父,叔叔连成一个闭合的图形的时候不是三角形,而是菱形。

如下图




最后完整的插入代码如下。跟nginx的红黑树的插入代码差不多。。因为我参照了。。还有一种写法就是像维基百科那样每个情况都用一个函数去写。那样可读性高。。。

[cpp] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. /* 
  2. ** tst_rbtree.h 
  3. ** create by lj 
  4. */  
  5.   
  6. #ifndef _TST_RBTREE_H_  
  7. #define _TST_RBTREE_H_  
  8.   
  9. #if 0  
  10. #define tst_rbt_inline inline   
  11. #else  
  12. #define tst_rbt_inline  
  13. #endif  
  14.   
  15. typedef struct tst_rbtnode_t tst_rbtnode;  
  16.   
  17. /* 树的节点结构 */  
  18. struct tst_rbtnode_t  
  19. {  
  20.     unsigned int    key;  
  21.     tst_rbtnode*        lchild;  
  22.     tst_rbtnode*        rchild;  
  23.     tst_rbtnode*        parent;  
  24.     unsigned char   color;  
  25.     unsigned char   data;  
  26. };  
  27.   
  28.   
  29. typedef struct tst_rbtree_t tst_rbtree;  
  30. typedef void(*tst_rbt_insert_func)(tst_rbtnode* root, tst_rbtnode* node, tst_rbtnode* sen);  
  31.   
  32. /* 树结构 */  
  33. struct tst_rbtree_t  
  34. {  
  35.     tst_rbtnode*    root;  
  36.     tst_rbtnode*    sentinel;//哨兵  
  37.     tst_rbt_insert_func insert;  
  38. };  
  39.   
  40. /* define */  
  41. #define tst_rbt_is_leaf(tree, n)    ((tree)->sentinel == (n))  
  42. #define tst_rbt_set_red(n)          ((n)->color = 1)  
  43. #define tst_rbt_set_black(n)        ((n)->color = 0)  
  44. #define tst_rbt_is_red(n)           ((n)->color)  
  45. #define tst_rbt_is_black(n)         (!tst_rbt_is_red(n))  
  46. #define tst_rbt_copy_color(n1,n2)   ((n1)->color = (n2)->color)  
  47. #define tst_rbt_parent(n)           ((n)->parent)  
  48. #define tst_rbt_grandpa(n)          (((n)->parent)->parent)  
  49. #define tst_rbt_is_lchild(n)        ((n)==(tst_rbt_parent(n)->lchild))  
  50. #define tst_rbt_is_rchild(n)        ((n)==(tst_rbt_parent(n)->rchild))  
  51.   
  52. #define tst_rbt_sibling(n)          (tst_rbt_parent(n)->lchild==(n)  \  
  53.                                     ?tst_rbt_parent(n)->rchild   \  
  54.                                     :tst_rbt_parent(n)->lchild)  
  55.   
  56. #define tst_rbt_lruncle(n,lr)           (tst_rbt_grandpa(n)->lr##child)  
  57.   
  58. #define tst_rbt_uncle(n)            ((tst_rbt_parent(n)==(tst_rbt_grandpa(n)->lchild))   \  
  59.                                     ?(tst_rbt_grandpa(n)->rchild)                \  
  60.                                     :(tst_rbt_grandpa(n)->lchild))  
  61.   
  62. #define tst_rbt_init(tree, psentinel, i)        \  
  63. do                                          \  
  64. {                                           \  
  65.     tst_rbt_set_black(psentinel);               \  
  66.     (tree)->root = psentinel;                \  
  67.     (tree)->sentinel = psentinel;            \  
  68.     (tree)->insert = i;                      \  
  69. while (0)  
  70.   
  71. #define tst_rbt_node_init(node, nkey )          \  
  72. do                                          \  
  73. {                                           \  
  74.     memset(node, 0x00, sizeof(tst_rbtnode));    \  
  75.     (node)->key = nkey;                      \  
  76. while (0)  
  77.   
  78. #define tst_rbt_node_reset(node) tst_rbt_node_init(node, 0)  
  79.   
  80. /* 一些操作函数 */  
  81. void tst_rbt_insert_default(tst_rbtnode* parent, tst_rbtnode* node, tst_rbtnode* sentinel);  
  82. void tst_rbt_insert(tst_rbtree* tree, tst_rbtnode* node);  
  83. void tst_rbt_delete(tst_rbtree* tree, tst_rbtnode* node);  
  84. void tst_rbt_free(tst_rbtree* tree);  
  85.   
  86. tst_rbtnode* tst_rbt_find(tst_rbtree* tree, tst_rbtnode* sentinel,unsigned int key);  
  87.   
  88. tst_rbt_inline tst_rbtnode* tst_rbt_min_node(tst_rbtnode* node, tst_rbtnode* sentinel);  
  89.   
  90. #endif  
/*** tst_rbtree.h** create by lj*/
#ifndef _TST_RBTREE_H_#define _TST_RBTREE_H_#if 0#define tst_rbt_inline inline #else#define tst_rbt_inline#endiftypedef struct tst_rbtnode_t tst_rbtnode;/* 树的节点结构 */struct tst_rbtnode_t{ unsigned int key; tst_rbtnode* lchild; tst_rbtnode* rchild; tst_rbtnode* parent; unsigned char color; unsigned char data;};typedef struct tst_rbtree_t tst_rbtree;typedef void(*tst_rbt_insert_func)(tst_rbtnode* root, tst_rbtnode* node, tst_rbtnode* sen);/* 树结构 */struct tst_rbtree_t{ tst_rbtnode* root; tst_rbtnode* sentinel;//哨兵 tst_rbt_insert_func insert;};/* define */#define tst_rbt_is_leaf(tree, n) ((tree)->sentinel == (n))#define tst_rbt_set_red(n) ((n)->color = 1)#define tst_rbt_set_black(n) ((n)->color = 0)#define tst_rbt_is_red(n) ((n)->color)#define tst_rbt_is_black(n) (!tst_rbt_is_red(n))#define tst_rbt_copy_color(n1,n2) ((n1)->color = (n2)->color)#define tst_rbt_parent(n) ((n)->parent)#define tst_rbt_grandpa(n) (((n)->parent)->parent)#define tst_rbt_is_lchild(n) ((n)==(tst_rbt_parent(n)->lchild))#define tst_rbt_is_rchild(n) ((n)==(tst_rbt_parent(n)->rchild))#define tst_rbt_sibling(n) (tst_rbt_parent(n)->lchild==(n) \ ?tst_rbt_parent(n)->rchild \ :tst_rbt_parent(n)->lchild)#define tst_rbt_lruncle(n,lr) (tst_rbt_grandpa(n)->lr##child)#define tst_rbt_uncle(n) ((tst_rbt_parent(n)==(tst_rbt_grandpa(n)->lchild)) \ ?(tst_rbt_grandpa(n)->rchild) \ :(tst_rbt_grandpa(n)->lchild))#define tst_rbt_init(tree, psentinel, i) \do \{ \ tst_rbt_set_black(psentinel); \ (tree)->root = psentinel; \ (tree)->sentinel = psentinel; \ (tree)->insert = i; \} while (0)#define tst_rbt_node_init(node, nkey ) \do \{ \ memset(node, 0x00, sizeof(tst_rbtnode)); \ (node)->key = nkey; \} while (0)#define tst_rbt_node_reset(node) tst_rbt_node_init(node, 0)/* 一些操作函数 */void tst_rbt_insert_default(tst_rbtnode* parent, tst_rbtnode* node, tst_rbtnode* sentinel);void tst_rbt_insert(tst_rbtree* tree, tst_rbtnode* node);void tst_rbt_delete(tst_rbtree* tree, tst_rbtnode* node);void tst_rbt_free(tst_rbtree* tree);tst_rbtnode* tst_rbt_find(tst_rbtree* tree, tst_rbtnode* sentinel,unsigned int key);tst_rbt_inline tst_rbtnode* tst_rbt_min_node(tst_rbtnode* node, tst_rbtnode* sentinel);#endif


源文件:

[cpp] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. /* 
  2. ** tst_rbtree.c 
  3. ** create by lj 
  4. */  
  5.   
  6. #include <assert.h>  
  7. #include <stdio.h>  
  8. #include <string.h>  
  9. #include “tst_rbtree.h”  
  10.   
  11.   
  12. static tst_rbt_inline void tst_rbt_rotate_left(tst_rbtnode** root, tst_rbtnode* node, tst_rbtnode* sentinel);  
  13. static tst_rbt_inline void tst_rbt_rotate_right(tst_rbtnode** root, tst_rbtnode* node, tst_rbtnode* sentinel);  
  14.   
  15. /* 
  16. * 二叉查找树的插入 
  17. */  
  18. void tst_rbt_insert_default(tst_rbtnode* parent, tst_rbtnode* node, tst_rbtnode* sentinel)  
  19. {  
  20.     tst_rbtnode** p;  
  21.   
  22.     for (;;)//为啥有的人喜欢for做死循环呢?因为编译优化之后是一个jmp,而while(true)还需要test或者cmp比较。多指令  
  23.     {  
  24.         p = (node->key < parent->key) ? &parent->lchild : &parent->rchild;  
  25.         if (*p == sentinel) //找到了叶子节点上了  
  26.         {  
  27.             break;  
  28.         }  
  29.         parent = *p;  
  30.     }  
  31.   
  32.     //当前结点插在叶子节点的位置  
  33.     *p = node;  
  34.     node->parent = parent;  
  35.     node->lchild = sentinel;  
  36.     node->rchild = sentinel;  
  37.     //当前结点为红色。运气好的话,父节点颜色是黑色,还不用调整。  
  38.     tst_rbt_set_red(node);  
  39. }  
  40.   
  41. void tst_rbt_insert(tst_rbtree* tree, tst_rbtnode* node)  
  42. {  
  43.     assert(tree && node);  
  44.   
  45.     tst_rbtnode *sen, **root;  
  46.     root = &tree->root;  
  47.     sen = tree->sentinel;  
  48.   
  49.     /* 新插入的点是根节点 */  
  50.     if (*root == sen)  
  51.     {  
  52.         *root = node;  
  53.         node->parent = NULL;  
  54.         node->lchild = sen;  
  55.         node->rchild = sen;  
  56.         tst_rbt_set_black(node);  
  57.   
  58.         return;  
  59.     }  
  60.   
  61.     //调用上面的tst_rbt_insert_default()  
  62.     tree->insert(*root, node, sen);  
  63.   
  64.     /* 重新平衡红黑树 */  
  65.     while (node != *root && tst_rbt_is_red(tst_rbt_parent(node)))  
  66.     {  
  67.         //node父节点是红色  
  68.         if (tst_rbt_parent(node) == tst_rbt_grandpa(node)->lchild)  
  69.         {     
  70.             //父节点是祖父的左孩子  
  71.             if (tst_rbt_is_red(tst_rbt_lruncle(node, r)))  
  72.             {  
  73.                 //叔叔是红色。调整颜色  
  74.                 tst_rbt_set_red(tst_rbt_grandpa(node));  
  75.                 tst_rbt_set_black(tst_rbt_parent(node));  
  76.                 tst_rbt_set_black(tst_rbt_lruncle(node, r));  
  77.                 node = tst_rbt_grandpa(node);  
  78.                 //循环回去再看node的parent的情况  
  79.                 //假如最后到根节点,这个时候根节点设置成红色。需要后面设置根节点为黑色  
  80.             }  
  81.             else  
  82.             {  
  83.                 //叔叔是黑色。旋转树  
  84.                 if (tst_rbt_is_rchild(node))  
  85.                 {  
  86.                     //父节点是左孩子,自己是右孩子,这个时候就是自己,父亲,祖父,叔叔连成闭合图形是菱形  
  87.                     node = tst_rbt_parent(node);  
  88.                     tst_rbt_rotate_left(root, node, sen);  
  89.                 }  
  90.                 tst_rbt_set_red(tst_rbt_grandpa(node));  
  91.                 tst_rbt_set_black(tst_rbt_parent(node));  
  92.                 tst_rbt_rotate_right(root, tst_rbt_grandpa(node), sen);  
  93.                 //旋转之后就ok,循环结束  
  94.             }  
  95.         }  
  96.         else  
  97.         {     
  98.             //父节点是祖父的右孩子,与上面是左孩子的操作相反就好。  
  99.             if (tst_rbt_is_red(tst_rbt_lruncle(node,l)))  
  100.             {     
  101.                 //叔叔是红色。调整颜色  
  102.                 tst_rbt_set_red(tst_rbt_grandpa(node));  
  103.                 tst_rbt_set_black(tst_rbt_parent(node));  
  104.                 tst_rbt_set_black(tst_rbt_lruncle(node,l));  
  105.                 node = tst_rbt_grandpa(node);  
  106.             }  
  107.             else  
  108.             {  
  109.                 if (tst_rbt_is_lchild(node))  
  110.                 {  
  111.                     node = tst_rbt_parent(node);  
  112.                     tst_rbt_rotate_right(root, node, sen);  
  113.                 }  
  114.                 tst_rbt_set_red(tst_rbt_grandpa(node));  
  115.                 tst_rbt_set_black(tst_rbt_parent(node));  
  116.                 tst_rbt_rotate_left(root, tst_rbt_grandpa(node), sen);  
  117.             }  
  118.   
  119.         }  
  120.     }  
  121.     tst_rbt_set_black(*root);  
  122.     return;  
  123. }  
  124.   
  125. /************************************************************************************* 
  126. **    如下图:20 这个节点左旋 或者 右旋 
  127. **                                                                                    
  128. **           30                  30                   10                   10         
  129. **           / \                 / \                  / \                  / \        
  130. **          20  31    左旋      22   31                9   20      左旋     9   22      
  131. **         / \      ——->   / \          或者        / \     ——->     / \       
  132. **       18  22    <——-   20  23                  18   22  <——–   20   23   
  133. **           / \      右旋   / \                             / \   右旋     / \          
  134. **         21   23          18  21                        21  23        18   21      
  135. **                                                                                      
  136. ***************************************************************************************/  
  137. static tst_rbt_inline void   
  138. tst_rbt_rotate_left(tst_rbtnode** root, tst_rbtnode* node, tst_rbtnode* sentinel)  
  139. {  
  140.     tst_rbtnode* temp;  
  141.   
  142.     temp = node->rchild;  
  143.     node->rchild = temp->lchild;  //相当于把21变成20的右孩子  
  144.   
  145.     if (temp->lchild != sentinel)  
  146.     {  
  147.         temp->lchild->parent = node;//21位置改变之后,重新设置他的parent  
  148.     }  
  149.     if (node == *root)  
  150.     {  
  151.         *root = temp;               //如果node是根节点。则temp是根节点  
  152.     }  
  153.     else if (node == tst_rbt_parent(node)->lchild )  
  154.     {  
  155.         tst_rbt_parent(node)->lchild = temp;//第一图,node在父节点的左孩子节点  
  156.     }  
  157.     else  
  158.     {  
  159.         tst_rbt_parent(node)->rchild = temp;//第二图,node在父节点的右孩子节点  
  160.     }  
  161.     temp->parent = tst_rbt_parent(node);  
  162.     temp->lchild = node;  
  163.     node->parent = temp;  
  164.   
  165. }  
  166.   
  167. static tst_rbt_inline void   
  168. tst_rbt_rotate_right(tst_rbtnode** root, tst_rbtnode* node, tst_rbtnode* sentinel)  
  169. {  
  170.     tst_rbtnode* temp;  
  171.     temp = node->lchild;  
  172.     node->lchild = temp->rchild;  
  173.   
  174.     if (temp->rchild != sentinel)  
  175.     {  
  176.         temp->rchild->parent = node;  
  177.     }  
  178.   
  179.     if (node == *root)  
  180.     {  
  181.         *root = temp;  
  182.     }  
  183.     else if (node == tst_rbt_parent(node)->lchild)  
  184.     {  
  185.         tst_rbt_parent(node)->lchild = temp;  
  186.     }  
  187.     else  
  188.     {  
  189.         tst_rbt_parent(node)->rchild = temp;  
  190.     }  
  191.     temp->parent = tst_rbt_parent(node);  
  192.     temp->rchild = node;  
  193.     node->parent = temp;  
  194. }  
/*** tst_rbtree.c** create by lj*/
#include <assert.h>#include <stdio.h>#include <string.h>#include "tst_rbtree.h"static tst_rbt_inline void tst_rbt_rotate_left(tst_rbtnode** root, tst_rbtnode* node, tst_rbtnode* sentinel);static tst_rbt_inline void tst_rbt_rotate_right(tst_rbtnode** root, tst_rbtnode* node, tst_rbtnode* sentinel);/** 二叉查找树的插入*/void tst_rbt_insert_default(tst_rbtnode* parent, tst_rbtnode* node, tst_rbtnode* sentinel){ tst_rbtnode** p; for (;;)//为啥有的人喜欢for做死循环呢?因为编译优化之后是一个jmp,而while(true)还需要test或者cmp比较。多指令 { p = (node->key < parent->key) ? &parent->lchild : &parent->rchild; if (*p == sentinel) //找到了叶子节点上了 { break; } parent = *p; } //当前结点插在叶子节点的位置 *p = node; node->parent = parent; node->lchild = sentinel; node->rchild = sentinel; //当前结点为红色。运气好的话,父节点颜色是黑色,还不用调整。 tst_rbt_set_red(node);}void tst_rbt_insert(tst_rbtree* tree, tst_rbtnode* node){ assert(tree && node); tst_rbtnode *sen, **root; root = &tree->root; sen = tree->sentinel; /* 新插入的点是根节点 */ if (*root == sen) { *root = node; node->parent = NULL; node->lchild = sen; node->rchild = sen; tst_rbt_set_black(node); return; } //调用上面的tst_rbt_insert_default() tree->insert(*root, node, sen); /* 重新平衡红黑树 */ while (node != *root && tst_rbt_is_red(tst_rbt_parent(node))) { //node父节点是红色 if (tst_rbt_parent(node) == tst_rbt_grandpa(node)->lchild) { //父节点是祖父的左孩子 if (tst_rbt_is_red(tst_rbt_lruncle(node, r))) { //叔叔是红色。调整颜色 tst_rbt_set_red(tst_rbt_grandpa(node)); tst_rbt_set_black(tst_rbt_parent(node)); tst_rbt_set_black(tst_rbt_lruncle(node, r)); node = tst_rbt_grandpa(node); //循环回去再看node的parent的情况 //假如最后到根节点,这个时候根节点设置成红色。需要后面设置根节点为黑色 } else { //叔叔是黑色。旋转树 if (tst_rbt_is_rchild(node)) { //父节点是左孩子,自己是右孩子,这个时候就是自己,父亲,祖父,叔叔连成闭合图形是菱形 node = tst_rbt_parent(node); tst_rbt_rotate_left(root, node, sen); } tst_rbt_set_red(tst_rbt_grandpa(node)); tst_rbt_set_black(tst_rbt_parent(node)); tst_rbt_rotate_right(root, tst_rbt_grandpa(node), sen); //旋转之后就ok,循环结束 } } else { //父节点是祖父的右孩子,与上面是左孩子的操作相反就好。 if (tst_rbt_is_red(tst_rbt_lruncle(node,l))) { //叔叔是红色。调整颜色 tst_rbt_set_red(tst_rbt_grandpa(node)); tst_rbt_set_black(tst_rbt_parent(node)); tst_rbt_set_black(tst_rbt_lruncle(node,l)); node = tst_rbt_grandpa(node); } else { if (tst_rbt_is_lchild(node)) { node = tst_rbt_parent(node); tst_rbt_rotate_right(root, node, sen); } tst_rbt_set_red(tst_rbt_grandpa(node)); tst_rbt_set_black(tst_rbt_parent(node)); tst_rbt_rotate_left(root, tst_rbt_grandpa(node), sen); } } } tst_rbt_set_black(*root); return;}/*************************************************************************************** 如下图:20 这个节点左旋 或者 右旋** ** 30 30 10 10 ** / \ / \ / \ / \ ** 20 31 左旋 22 31 9 20 左旋 9 22 ** / \ -------> / \ 或者 / \ -------> / \ ** 18 22 <------- 20 23 18 22 <-------- 20 23 ** / \ 右旋 / \ / \ 右旋 / \ ** 21 23 18 21 21 23 18 21 ** ***************************************************************************************/static tst_rbt_inline void tst_rbt_rotate_left(tst_rbtnode** root, tst_rbtnode* node, tst_rbtnode* sentinel){ tst_rbtnode* temp; temp = node->rchild; node->rchild = temp->lchild; //相当于把21变成20的右孩子 if (temp->lchild != sentinel) { temp->lchild->parent = node;//21位置改变之后,重新设置他的parent } if (node == *root) { *root = temp; //如果node是根节点。则temp是根节点 } else if (node == tst_rbt_parent(node)->lchild ) { tst_rbt_parent(node)->lchild = temp;//第一图,node在父节点的左孩子节点 } else { tst_rbt_parent(node)->rchild = temp;//第二图,node在父节点的右孩子节点 } temp->parent = tst_rbt_parent(node); temp->lchild = node; node->parent = temp;}static tst_rbt_inline void tst_rbt_rotate_right(tst_rbtnode** root, tst_rbtnode* node, tst_rbtnode* sentinel){ tst_rbtnode* temp; temp = node->lchild; node->lchild = temp->rchild; if (temp->rchild != sentinel) { temp->rchild->parent = node; } if (node == *root) { *root = temp; } else if (node == tst_rbt_parent(node)->lchild) { tst_rbt_parent(node)->lchild = temp; } else { tst_rbt_parent(node)->rchild = temp; } temp->parent = tst_rbt_parent(node); temp->rchild = node; node->parent = temp;}

以上说明、代码如果有什么问题,请斧正,感激不尽。

谢谢!

0 0
原创粉丝点击