`

红黑树 转载 C语言实现

    博客分类:
  • web
 
阅读更多

红黑树是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。它是在1972年由Rudolf Bayer发明的,他称之为"对称二叉B树",它现代的名字是在 Leo J. Guibas 和 Robert Sedgewick 于1978年写的一篇论文中获得的。它是复杂的,但它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。

红黑树是一种很有意思的平衡检索树。它的统计性能要好于平衡二叉树(有些书籍根据作者姓名,Adelson-Velskii和Landis,将其称为AVL-树),因此,红黑树在很多地方都有应用。在C++ STL中,很多部分(目前包括set, multiset, map, multimap)应用了红黑树的变体(SGI STL中的红黑树有一些变化,这些修改提供了更好的性能,以及对set操作的支持)。

 

点击(此处)折叠或打开

  1. /* 
  2. 性质1. 节点是红色或黑色 
  3. 性质2. 根是黑色 
  4. 性质3. 每个红色节点的两个子节点都是黑色 (从每个叶子到根的所有路径上不能有两个连续的红色节点) 
  5. 性质4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点 
  6. */ 
  7.   
  8. #include <stdio.h> 
  9. #include <stdlib.h> 
  10. typedef enum Color //定义红黑树结点颜色颜色类型 
  11. { 
  12.     RED = 0, 
  13.     BLACK = 1 
  14. }Color; 
  15.   
  16. typedef struct Node //定义红黑树结点类型 
  17. { 
  18.     struct Node *parent; 
  19.     struct Node *left; 
  20.     struct Node *right; 
  21.     int value; 
  22.     Color color; 
  23. }Node, *Tree; 
  24. Node *nil=NULL; //为了避免讨论结点的边界情况,定义一个nil结点代替所有的NULL 
  25.   
  26. Node* Parent(Node *z) //返回某结点的父母 
  27. { 
  28.     return z->parent; 
  29. } 
  30. Node* Left(Node *z) //返回左子树 
  31. { 
  32.     return z->left; 
  33. } 
  34. Node *Right(Node *z) //返回右子树 
  35. { 
  36.     return z->right; 
  37. } 
  38. void LeftRotate(Tree &T, Node *x) //左旋转:结点x原来的右子树y旋转成为x的父母 
  39. { 
  40.     if( x-> right != nil ) 
  41.     { 
  42.         Node *y=Right(x); 
  43.         x->right=y->left; 
  44.         if(y->left != nil) 
  45.         { 
  46.             y->left->parent=x; 
  47.         } 
  48.         y->parent=x->parent; 
  49.         if( x->parent == nil ) 
  50.         { 
  51.             T=y; 
  52.         } 
  53.         else 
  54.         { 
  55.             if( x == Left(Parent(x)) ) 
  56.             { 
  57.                 x->parent->left=y; 
  58.             } 
  59.             else 
  60.             { 
  61.                 x->parent->right=y; 
  62.             } 
  63.         } 
  64.         y->left=x; 
  65.         x->parent=y; 
  66.     } 
  67.     else 
  68.     { 
  69.         printf("%s/n","can't execute left rotate due to null right child"); 
  70.     } 
  71. } 
  72.   
  73. void RightRotate(Tree &T, Node *x) //右旋转:结点x原来的左子树y旋转成为x的父母 
  74. { 
  75.     if( x->left != nil ) 
  76.     { 
  77.         Node *y=Left(x); 
  78.         x->left=y->right; 
  79.         if( y->right != nil ) 
  80.         { 
  81.             y->right->parent=x; 
  82.         } 
  83.         y->parent=x->parent; 
  84.         if( x->parent == nil ) 
  85.         { 
  86.             T=y; 
  87.         } 
  88.         else 
  89.         { 
  90.             if(== Left(Parent(x)) ) 
  91.             { 
  92.                 x->parent->left=y; 
  93.             } 
  94.             else 
  95.             { 
  96.                 x->parent->right=y; 
  97.             } 
  98.         } 
  99.         y->right=x; 
  100.         x->parent=y; 
  101.     } 
  102.     else 
  103.     { 
  104.         printf("%s/n","can't execute right rotate due to null left child"); 
  105.     } 
  106.   
  107. } 
  108.   
  109. void InsertFixup(Tree &T, Node *z) //插入结点后, 要维持红黑树四条性质的不变性 
  110. { 
  111.     Node *y; 
  112.     while( Parent(z)->color == RED ) //因为插入的结点是红色的,所以只可能违背性质3,即假如父结点也是红色的,要做调整 
  113.     { 
  114.         if( Parent(Parent(z))->left == Parent(z) ) //如果要插入的结点z是其父结点的左子树 
  115.         { 
  116.             y=Parent(Parent(z))->right; // y设置为z的叔父结点 
  117.             if( y->color == RED ) //case 1: 如果y的颜色为红色,那么将y与z的父亲同时着为黑色,然后把z的 
  118.             { //祖父变为红色,这样子z的祖父结点可能违背性质3,将z上移成z的祖父结点 
  119.                 y->color=BLACK; 
  120.                 z->parent->color=BLACK; 
  121.                 z->parent->parent->color=RED; 
  122.                 z=z->parent->parent; 
  123.             } 
  124.             else 
  125.             { 
  126.                 if( z == z->parent->right ) //case 2: 如果y的颜色为黑色,并且z是z的父母的右结点,则z左旋转,并且将z变为原来z的parent. 
  127.                 { 
  128.                     z=z->parent; 
  129.                     LeftRotate(T, z); 
  130.                 } 
  131.                 z->parent->color=BLACK; //case 3: 如果y的颜色为黑色,并且z是z的父母的左结点,那么将z的 
  132.                 z->parent->parent->color=RED; //父亲的颜色变为黑,将z的祖父的颜色变为红,然后旋转z的祖父 
  133.                 RightRotate(T,z->parent->parent); 
  134.             } 
  135.         } 
  136.         else //与前一种情况对称,要插入的结点z是其父结点的右子树,注释略去 
  137.         { 
  138.             y=Parent(Parent(z))->left; 
  139.             if( y->color == RED) 
  140.             { 
  141.                 z->parent->color=BLACK; 
  142.                 y->color=BLACK; 
  143.                 z->parent->parent->color=RED; 
  144.                 z=z->parent->parent; 
  145.             } 
  146.             else 
  147.             { 
  148.                 if( z == z->parent->left ) 
  149.                 { 
  150.                     z=z->parent; 
  151.                     RightRotate(T,z); 
  152.                 } 
  153.                 z->parent->color=BLACK; 
  154.                 z->parent->parent->color=RED; 
  155.                 LeftRotate(T,z->parent->parent); 
  156.             } 
  157.         } 
  158.     } 
  159.     T->color=BLACK; //最后如果上升为T的根的话,把T的颜色设置为黑色 
  160. } 
  161. void Insert(Tree &T, int val) //插入结点 
  162. { 
  163.     if(== NULL) //初始化工作:如果根尚不存在,那么new一个新结点给根,同时new一个新结点给nil 
  164.     { 
  165.         T=(Tree)malloc(sizeof(Node)); 
  166.         nil=(Node*)malloc(sizeof(Node)); 
  167.         nil->color=BLACK; //nil的颜色设置为黑 
  168.         T->left=nil; 
  169.         T->right=nil; 
  170.         T->parent=nil; 
  171.         T->value=val; 
  172.         T->color=BLACK; //为了满足性质2,根的颜色设置为黑色 
  173.     } 
  174.     else //如果此树已经不为空,那么从根开始,从上往下查找插入点 
  175.     { 
  176.         Node *x=T; //用x保存当前顶点的父母结点,用p保存当前的结点 
  177.         Node *p=nil; 
  178.         while(!= nil) //如果val小于当前结点的value值,则从左边下去,否则从右边下去 
  179.         { 
  180.             p=x; 
  181.             if(val < x->value ) 
  182.             { 
  183.                 x=x->left; 
  184.             } 
  185.             else if(val > x->value) 
  186.             { 
  187.                 x=x->right; 
  188.             } 
  189.             else 
  190.             { 
  191.                 printf("%s %d/n","duplicate value",val); //如果查找到与val值相同的结点,则什么也不做,直接返回 
  192.                 return; 
  193.             } 
  194.   
  195.         } 
  196.         x=(Node*)malloc(sizeof(Node)); 
  197.         x->color=RED; //新插入的结点颜色设置为红色 
  198.         x->left=nil; 
  199.         x->right=nil; 
  200.         x->parent=p; 
  201.         x->value=val; 
  202.         if( val < p->value ) 
  203.         { 
  204.             p->left = x; 
  205.         } 
  206.         else 
  207.         { 
  208.             p->right = x; 
  209.         } 
  210.           
  211.         InsertFixup(T, x); //插入后对树进行调整 
  212.           
  213.     } 
  214. } 
  215.   
  216. Node* Successor(Tree &T, Node *x) //寻找结点x的中序后继 
  217. { 
  218.     if( x->right != nil ) //如果x的右子树不为空,那么为右子树中最左边的结点 
  219.     { 
  220.         Node *q=nil; 
  221.         Node *p=x->right; 
  222.         while( p->left != nil ) 
  223.         { 
  224.             q=p; 
  225.             p=p->left; 
  226.         } 
  227.         return q; 
  228.     } 
  229.     else //如果x的右子树为空,那么x的后继为x的所有祖先中为左子树的祖先 
  230.     { 
  231.         Node *y=x->parent; 
  232.         while( y != nil && x == y->right ) 
  233.         { 
  234.             x=y; 
  235.             y=y->parent; 
  236.         } 
  237.           
  238.         return y; 
  239.     } 
  240. } 
  241.   
  242. void DeleteFixup(Tree &T, Node *x) //删除黑色结点后,导致黑色缺失,违背性质4,故对树进行调整 
  243. { 
  244.     while( x != T && x->color == BLACK ) //如果x是红色,则直接把x变为黑色跳出循环,这样子刚好补了一重黑色,也满足了性质4 
  245.     { 
  246.         if( x == x->parent->left ) //如果x是其父结点的左子树 
  247.         { 
  248.             Node *w=x->parent->right; //设w是x的兄弟结点 
  249.             if( w->color == RED ) //case 1: 如果w的颜色为红色的话 
  250.             { 
  251.                 w->color=BLACK; 
  252.                 x->parent->color=RED; 
  253.                 LeftRotate(T, x->parent); 
  254.                 w=x->parent->right; 
  255.             } 
  256.             if( w->left->color == BLACK && w->right->color == BLACK ) //case 2: w的颜色为黑色,其左右子树的颜色都为黑色 
  257.             { 
  258.                 w->color=RED; 
  259.                 x=x->parent; 
  260.             } 
  261.             else if( w->right->color == BLACK ) //case 3: w的左子树是红色,右子树是黑色的话 
  262.             { 
  263.                 w->color=RED; 
  264.                 w->left->color=BLACK; 
  265.                 RightRotate(T, w); 
  266.                 w=x->parent->right; 
  267.             } 
  268.             w->color=x->parent->color; //case 4: w的右子树是红色 
  269.             x->parent->color=BLACK; 
  270.             w->right->color=BLACK; 
  271.             LeftRotate(, x->parent); 
  272.               
  273.             x=T; 
  274.         } 
  275.         else //对称情况,如果x是其父结点的右子树 
  276.         { 
  277.             Node *w=x->parent->left; 
  278.             if( w->color == RED ) 
  279.             { 
  280.                 w->color=BLACK; 
  281.                 x->parent->color=RED; 
  282.                 RightRotate(T, x->parent); 
  283.                 w=x->parent->left; 
  284.             } 
  285.             if( w->left->color == BLACK && w->right->color == BLACK ) 
  286.             { 
  287.                 w->color=RED; 
  288.                 x=x->parent; 
  289.             } 
  290.             else if( w->left->color == BLACK ) 
  291.             { 
  292.                 w->color=RED; 
  293.                 w->right->color=BLACK; 
  294.                 LeftRotate(T, w); 
  295.                 w=x->parent->left; 
  296.             } 
  297.             w->color=x->parent->color; 
  298.             x->parent->color=BLACK; 
  299.             w->left->color=BLACK; 
  300.             RightRotate(, x->parent); 
  301.               
  302.             x=T; 
  303.               
  304.         } 
  305.     } 
  306.     x->color=BLACK; 
  307. } 
  308.   
  309. void Delete(Tree &T, Node *z) //在红黑树T中删除结点z 
  310. { 
  311.     Node *y; //y指向将要被删除的结点 
  312.     Node *x; //x指向将要被删除的结点的唯一儿子 
  313.     if( z->left == nil || z->right == nil ) //如果z有一个子树为空的话,那么将直接删除z,即y指向z 
  314.     { 
  315.         y=z; 
  316.     } 
  317.     else 
  318.     { 
  319.         y=Successor(T, z); //如果z的左右子树皆不为空的话,则寻找z的中序后继y, 
  320.     } //用其值代替z的值,然后将y删除 ( 注意: y肯定是没有左子树的 ) 
  321.     if( y->left != nil ) //如果y的左子树不为空,则x指向y的左子树 
  322.     { 
  323.         x=y->left; 
  324.     } 
  325.     else 
  326.     { 
  327.         x=y->right; 
  328.     } 
  329.     x->parent=y->parent; //将原来y的父母设为x的父母,y即将被删除 
  330.     if( y->parent == nil ) 
  331.     { 
  332.         T=x; 
  333.     } 
  334.     else 
  335.     { 
  336.         if( y == y->parent->left ) 
  337.         { 
  338.             y->parent->left=x; 
  339.         } 
  340.         else 
  341.         { 
  342.             y->parent->right=x; 
  343.         } 
  344.     } 
  345.     if( y != z ) //如果被删除的结点y不是原来将要删除的结点z, 
  346.     { //即只是用y的值来代替z的值,然后变相删除y以达到删除z的效果 
  347.         z->value=y->value; 
  348.     } 
  349.     if( y->color == BLACK ) //如果被删除的结点y的颜色为黑色,那么可能会导致树违背性质4,导致某条路径上少了一个黑色 
  350.     { 
  351.         DeleteFixup(T, x); 
  352.     } 
  353. } 
  354. Node* Search(Tree T, int val) 
  355. { 
  356.     if( T != nil ) 
  357.     { 
  358.         if( val < T->value ) 
  359.         { 
  360.             Search(T->left, val); 
  361.         } 
  362.         else if ( val > T->value ) 
  363.         { 
  364.             Search(T->right,val); 
  365.         } 
  366.         else 
  367.         { 
  368.             return T; 
  369.         } 
  370.     } 
  371. } 
  372.   
  373. void MidTranverse(Tree T) 
  374. { 
  375.     if( T != NULL && T != nil ) 
  376.     { 
  377.         MidTranverse(T->left); 
  378.         printf("%d ",T->value); 
  379.         MidTranverse(T->right); 
  380.     } 
  381.   
  382. } 
  383. int main() 
  384. { 
  385.     Tree t=NULL; 
  386.     Insert(t,30); 
  387.     Insert(t,50); 
  388.     Insert(t,65); 
  389.     Insert(t,80); 
  390.     Delete(t,Search(t,30)); 
  391.     Delete(t,Search(t,65)); 
  392.     MidTranverse(t); 
  393.     return 0; 
  394. }




参考文献:
1,http://blog.csdn.net/fantasywindy/article/details/5752434
2,http://www.linuxidc.com/Linux/2011-07/39027.htm
3,http://blog.chinaunix.net/uid-28458801-id-4043737.html

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics