算法导论 动态顺序统计与区间树

来源:互联网 发布:天正电气软件下载 编辑:程序博客网 时间:2024/04/28 23:39
  • 本文的基础是红黑树 算法导论–红黑树

    通过在基础的数据结构中添加一些附加信息,来扩张一种标准的数据结构,然后编写新的操作来支持所需要的应用。下面是介绍在红黑树的基础上扩张的数据结构。

    1.动态顺序统计

    动态顺序统计可以在O(lgn)时间内确定任何的顺序统计量(即在n个元素的集合中,能在O(lgn)的时间内确定第i小的元素),同时也可以在O(lgn)的时间内计算一个元素的秩(即它在中序遍历下的位置顺序)。

    添加附加信息

    结点x中加入x.size , size的大小为以x为根的子树(包含x本身)的内结数,即子树的大小。我们定义哨兵的size为0,如下图: 
    \ 
    结点内,虚线上方为关键字key,下方为结点的size。 
    可以看出: x.size = x.left.size + x.right.size +1;

    view sourceprint?
    01.<code class=" hljs d">enum colors{red,black};//枚举类型
    02.typedef struct Node
    03.{
    04.struct Node * p;
    05.struct Node *left;
    06.struct Node *right;
    07.int key;            
    08.enum  colors color;  //颜色属性
    09.int size;           //新添加的属性size
    10.}Node;</code>

    修改基本操作

    插入操作: 
    为了对子树规模的维护,需要在不影响插入和删除操作的渐进运行时间的前提下,修改基本的操作。 
    第一阶段:新节点的插入过程中,需要对从根到将要插入的位置过程中遍历的结点的size加1; 
    第二阶段:维护红黑树的左旋和右旋函数需要在最后添加以下语句: 
    \

    view sourceprint?
    1.<code class=" hljs avrasm"/*左旋*/
    2.y.size = x.size;
    3.x.size = x.left.size + x.right.size +1;
    4./*右旋*/
    5.x.size = y.size;
    6.y.size = y.left.size + y.right.size +1;</code>

    删除操作: 
    第一阶段:如果要删除的结点z少于两个孩子,则从z到根T的过程遍历的结点size减1;如果要删除的结点z多于两个孩子,则从z的后继y处向上到T的过程中,遍历的结点size减1; 
    第二阶段: 
    也是同样在左右旋过程中,添加以上的语句; 
    插入操作和删除操作运行时间都是O(lgn).

    设计新的操作

    1.给定秩的元素的检索 
    调用函数OS_Select(Node * x,int i)检索出在以x为根的子树中,第i小的关键字的结点。运行时间为O(lgn);

    view sourceprint?
    01.<code class=" hljs lasso">Node * OS_Select(Node *x,int i)
    02.{
    03.int r =x->left->size+1;           //计算以结点x为根的子树中顺序统计量r
    04.if (i == r)
    05.return x;  
    06.else if (i < r)               
    07.return OS_Select(x->left,i);  //在x的左子树里继续递归查找
    08.else
    09.return OS_Select(x->right,i-r);//在x的右子树里继续递归查找
    10.}</code>

    2.确定一个元素的秩 
    给定指向T中,结点x的指针,过程OS_Rank返回对T中序遍历对应的线性序中x的位置;运行时间为O(lgn)

    view sourceprint?
    01.<code class=" hljs lasso">int OS_Rank(Node *T,Node * x)
    02.{
    03.int r =x->left->size+1;  //计算以结点x为根的子树中顺序统计量r
    04.Node * y =x;
    05.while(y != T)                 //叠加到root根节点位置
    06.{
    07.if (y == y->p->right)          //父节点的右子树输出在左子树和根之后,顺序统计量叠加
    08.{
    09.r=r+y->p->left->size+1;
    10.}
    11.y = y->p;                      //若属于左子树,直接跳向上层
    12.}
    13.return r;
    14.}</code>

    完整代码

    view sourceprint?
    001.<code class=" hljs haskell">/*       
    002.CSDN 勿在浮砂筑高台
    003.http://blog.csdn.net/luoshixian099
    004.算法导论--顺序统计量
    005.2015年5月20日
    006.*/
    007.#include <STDIO.H>
    008.#include <STDLIB.H>
    009.enum colors{red,black};//枚举类型
    010.typedef struct Node
    011.{
    012.struct Node * p;
    013.struct Node *left;
    014.struct Node *right;
    015.int key;
    016.enum  colors color;
    017.int size;                       //添加附加信息size
    018.}Node;
    019.Node *T_NIL=NULL;                 //建立全部变量 T_NIL
    020. 
    021.Node * Tree_Minimum(Node * T)     //找最小结点
    022.{
    023.while(T->left != T_NIL)
    024.T=T->left;
    025.return T;
    026.}
    027.void Inorder_Tree_Walk(Node * T)  //中序遍历树T,输出
    028.{
    029.if ( T != T_NIL)
    030.{
    031.Inorder_Tree_Walk(T->left);   //递归其左孩子
    032.printf("%d",T->key);        //输出根的关键字
    033.if (T->color == 0)
    034.{
    035.printf("-R");
    036.}
    037.else
    038.{
    039.printf("-B");
    040.}
    041.printf("-(%d)  ",T->size);
    042.Inorder_Tree_Walk(T->right);  //递归其右孩子
    043.}
    044.}
    045.void Pre_Tree_Walk(Node * T)  //
    046.{
    047.if ( T != T_NIL)
    048.{    
    049.printf("%d    ",T->key);          //输出根的关键字
    050.Pre_Tree_Walk(T->left);   //递归其左孩子     
    051.Pre_Tree_Walk(T->right);  //递归其右孩子
    052. 
    053.}
    054.}
    055. 
    056.void Left_Rotate(Node **T,Node * x)   //左旋
    057.{
    058.Node *y=x->right;
    059. 
    060.x->right =y->left;
    061.if (y->left != T_NIL)
    062.y->left->p=x;
    063.y->p=x->p;
    064.if(x->p==T_NIL)
    065.*T=y;
    066.else if (x == x->p->left)
    067.x->p->left = y;
    068.else
    069.x->p->right = y;
    070.y->left = x;
    071.x->p=y;
    072. 
    073.y->size = x->size;                         //添加语句维护size
    074.x->size = x->left->size+x->right->size+1;
    075.}
    076.void Right_Rotate(Node **T,Node * y)   //右旋
    077.{
    078.Node *x=y->left;
    079. 
    080.y->left =x->right;
    081.if (x->right != T_NIL)
    082.x->right->p=y;
    083.x->p=y->p;
    084.if(y->p==T_NIL)
    085.*T=x;
    086.else if (y == y->p->left)
    087.y->p->left = x;
    088.else 
    089.y->p->right = x;
    090.x->right = y;
    091.y->p=x;
    092. 
    093.x->size = y->size;                     //添加语句维护size
    094.y->size = y->left->size+y->right->size+1;
    095.}
    096.Node* RB_Insert_Fixup(Node *T,Node *z)
    097.{
    098.Node * y=NULL;
    099.while( z->p->color == red)       //违反了性质4,迭代进行修正
    100.{
    101.if (z->p == z->p->p->left)
    102.{
    103.y = z->p->p->right;
    104.if ( y->color == red)    // case 1 叔结点为红色
    105.{
    106.z->p->color = black;    //父节点涂黑
    107.y->color = black;       //叔结点涂黑
    108.z->p->p->color = red;   //祖结点涂红
    109.z = z->p->p;            //向上迭代,更新z的位置
    110.}
    111.else if ( z == z->p->right) //case 2 叔结点为黑色且z为双亲的右孩子
    112.{
    113.z = z->p;
    114.Left_Rotate(&T,z);
    115.z->p->color = black;    //case2 已转为 case3 继续处理
    116.z->p->p->color = red;
    117.Right_Rotate(&T,z->p->p);// while循环终止
    118.}
    119.else                      // case 3 叔结点为黑色且z为双亲的左孩子
    120.{
    121.z->p->color = black;
    122.z->p->p->color = red;
    123.Right_Rotate(&T,z->p->p);//   while循环终止
    124.}
    125.}
    126. 
    127.else                      //对称处理
    128.{
    129. 
    130.y = z->p->p->left;
    131.if ( y->color == red)    // case 1 叔结点为红色
    132.{
    133.z->p->color = black;
    134.y->color = black;
    135.z->p->p->color = red;
    136.z = z->p->p;
    137.}
    138. 
    139.else if ( z == z->p->left) //case 2 叔结点为黑色且z为双亲的右孩子
    140.{
    141.z = z->p;
    142.Right_Rotate(&T,z);
    143.z->p->color = black;
    144.z->p->p->color = red;
    145.Left_Rotate(&T,z->p->p);//
    146.}
    147.else                      // case 3
    148.{
    149.z->p->color = black;
    150.z->p->p->color = red;
    151.Left_Rotate(&T,z->p->p);
    152.}
    153. 
    154.
    155.}
    156. 
    157.T->color = black;          //保证不会违反性质2,对根节点涂黑
    158.return T;
    159.}
    160.Node *RB_Insert(Node *Root,Node * z)   //红黑树插入,返回树的根
    161.{
    162.Node * y=T_NIL;
    163.Node * x=Root;
    164.while( x != T_NIL)                 //找到结点z要插入的位置   
    165.{
    166.x->size+=1;                    //插入过程中,遍历的结点size加1
    167. 
    168.y=x;
    169.if (z->key < x->key)
    170.x = x->left;
    171.else
    172.x = x->right;
    173.}
    174.z->p = y;
    175.if ( y == T_NIL)    //插入第一个结点作为根节点的情况 
    176.Root = z;
    177.else if (z->key < y->key)
    178.y->left = z;
    179.else   
    180.y->right = z;
    181. 
    182.Root = RB_Insert_Fixup(Root,z);    //插入完毕后,对红黑树的颜色进行修正
    183.return Root;
    184.}
    185.Node * Establish(int *A,int len)   //建立红黑树
    186.{
    187.Node * T,*node;
    188.int i=0;
    189.node=NULL;
    190.T_NIL=(Node *)malloc(sizeof(Node));  //建立T_NIL结点
    191.T_NIL->p=NULL;
    192.T_NIL->left=NULL;
    193.T_NIL->right=NULL;
    194.T_NIL->key=-1;
    195.T_NIL->color=black;
    196.T_NIL->size=0;
    197.T=T_NIL;
    198.for (i=0;i<len;i++)
    199.{
    200.node =(Node *)malloc(sizeof(Node));
    201.node->p =T_NIL;
    202.node->left=T_NIL;
    203.node->right=T_NIL;
    204.node->key=A[i];
    205.node->color=red;
    206.node->size=1;
    207.T=RB_Insert(T,node);
    208.}
    209.return T;
    210.}
    211. 
    212.void RB_Transplant(Node **T,Node * u,Node * v)  //结点替代函数
    213.{
    214.if (u->p == T_NIL)
    215.*T = v;
    216.else if (u == u->p->left)
    217.u->p->left = v;
    218.else
    219.u->p->right = v;
    220.v->p = u->p;               //此处赋值无条件,v如果是T_NIL也要进行赋值
    221.}
    222.void RB_Delete_Fixup(Node * T,Node * x)
    223.{
    224.Node *w=NULL;
    225.while( x != T && x->color == black)      //循环迭代处理
    226.{
    227.if ( x == x->p->left )
    228.{
    229.w = x->p->right;
    230.if (w->color == red)             // case 1 ------> case 2 , case 3 ,case 4
    231.{
    232.w->color = black;
    233.x->p->color =red;
    234.Left_Rotate(&T,x->p);
    235.w = x->p->right;
    236.}
    237.if ( w->left->color == black && w->right->color == black ) //case 2 ------>go on / stop
    238.{
    239.w->color = red;
    240.x = x->p;
    241.}
    242.else if ( w->right->color == black)   // case 3 ---->case 4---->stop
    243.{
    244.w->left->color = black;
    245.w->color =red ;
    246.Right_Rotate(&T,w);
    247. 
    248.w = x->p->right ;                   //转成case 4处理
    249.w->color = x->p->color;
    250.x->p->color = black;
    251.w->right->color = black;
    252.Left_Rotate(&T,x->p);
    253.x = T;
    254.}
    255.else                               // case 4 ------------------->stop
    256.{
    257.w->color = x->p->color;
    258.x->p->color = black;
    259.w->right->color = black;
    260.Left_Rotate(&T,x->p);
    261.x = T;
    262.}
    263.}
    264.else
    265.{
    266.w = x->p->left;
    267.if (w->color == red)                // case 1 ------> case 2 , case 3 ,case 4
    268.{
    269.w->color = black;
    270.x->p->color =red;
    271.Right_Rotate(&T,x->p);
    272.w = x->p->left;
    273.}
    274.if ( w->right->color == black && w->left->color == black ) //case 2 ------>go on/stop
    275.{
    276.w->color = red;
    277.x = x->p;
    278.}
    279.else if ( w->left->color == black)      // case 3 -----> case 4----->stop
    280.{
    281.w->right->color = black;
    282.w->color =red ;
    283.Left_Rotate(&T,w);
    284. 
    285.w = x->p->left ;                    //转成case 4处理
    286.w->color = x->p->color;
    287.x->p->color = black;
    288.w->left->color = black;
    289.Right_Rotate(&T,x->p);
    290.x = T;
    291.}
    292.else                                  // case 4 -------------->stop
    293.{
    294.w->color = x->p->color;
    295.x->p->color = black;
    296.w->left->color = black;
    297.Right_Rotate(&T,x->p);
    298.x = T;
    299.}
    300.}
    301.}
    302. 
    303.x->color = black;                       //可能由case2退出,那把x涂黑即可,见分析!也可能有case4退出,把根节点涂黑
    304.}
    305.Node * RB_Delete(Node *T ,Node *z)
    306.{
    307. 
    308.Node * x =NULL;
    309.Node * y =z;
    310.Node *temp=y->p;
    311.enum colors y_original_color = y->color;   //记录下删除前z的颜色
    312.if ( z->left == T_NIL)                     //左子树不存在的情况 
    313.{
    314.x = z->right;
    315.RB_Transplant(&T,z,z->right);
    316.}
    317.else if ( z->right == T_NIL)              //右子树不存在
    318.{
    319.x = z->left;
    320.RB_Transplant(&T,z,z->left);
    321.}
    322.else                                     //左右都存在的情况
    323.{
    324.y = Tree_Minimum(z->right);            //找到后继y
    325.temp=y->p;  
    326.y_original_color = y->color;           //记录下y转移前的颜色
    327.x = y->right;
    328.if ( y->p == z)                       //如果y是z的子结点
    329.{
    330.x->p = y;
    331.}
    332.else
    333.{
    334.RB_Transplant(&T,y,y->right);    //如果y不是z的子结点,用y的右子树代替y的位置
    335.y->right = z->right;
    336.y->right->p = y;
    337.}
    338.RB_Transplant(&T,z,y);           //y替代z的位置 ,不论y是不是T_NIL  
    339.y->left = z->left;
    340.y->left->p = y;
    341.y->color = z->color;             //把y的颜色改成z的颜色
    342. 
    343.y->size =y->left->size+y->right->size+1;
    344.}
    345. 
    346.while(temp != T_NIL)             //从删除的位置或后继的位置向上遍历size--,直到根节点为止
    347.{
    348.temp->size--;
    349.temp = temp->p;
    350.}
    351. 
    352. 
    353. 
    354.if ( y_original_color == black)   //判断y的颜色,若为黑色,需要修复
    355.RB_Delete_Fixup(T,x);
    356.return T;
    357.}
    358. 
    359.Node * Tree_Search(Node *T ,int k)  //寻找数k是否在树中,且返回数k的地址
    360.{  
    361. 
    362.while(T !=T_NIL && T->key != k)
    363.{
    364.if ( k < T->key)
    365.T=T->left;
    366.else
    367.T=T->right;
    368.}
    369. 
    370.if ( T == T_NIL)
    371.{    
    372.return NULL;
    373.}
    374. 
    375.else
    376.{
    377.return T;
    378.}
    379. 
    380.}
    381.Node * OS_Select(Node *x,int i)        //确定以x为根节点的子树,第i小的关键字
    382.{
    383.int r =x->left->size+1;
    384.if (i == r)
    385.return x;  
    386.else if (i < r)
    387.return OS_Select(x->left,i);
    388.else
    389.return OS_Select(x->right,i-r);
    390.}
    391.int OS_Rank(Node *T,Node * x)         //确定x在树T中序遍历中的位置顺序
    392.{
    393.int r =x->left->size+1;
    394.Node * y =x;
    395.while(y != T)
    396.{
    397.if (y == y->p->right)
    398.{
    399.r=r+y->p->left->size+1;
    400.}
    401.y = y->p;
    402.}
    403.return r;
    404.}
    405.void main()
    406.{
    407.int A[]={2,5,1,6,3,8,4,9,7};
    408. 
    409.int length = sizeof(A)/sizeof(A[0]); //数组A的长度
    410.Node *T =Establish(A,length);        //建立红黑树,返回根节点T
    411. 
    412.printf("中序遍历:\n");
    413.Inorder_Tree_Walk(T);printf("\n");   //中序遍历输出
    414. 
    415.printf("先序遍历:\n");              //先序遍历输出
    416.Pre_Tree_Walk(T);printf("\n");
    417. 
    418.printf("__%d__\n",OS_Select(T,5)->key);
    419.printf("--%d--\n",OS_Rank(T,Tree_Search(T,3)));
    420. 
    421.printf("-----------删除操作后-------------\n");
    422. 
    423.T=RB_Delete(T,Tree_Search(T,2));
    424.T=RB_Delete(T,Tree_Search(T,5));
    425.T=RB_Delete(T,Tree_Search(T,7));
    426.T=RB_Delete(T,Tree_Search(T,4));
    427.printf("中序遍历:\n");
    428.Inorder_Tree_Walk(T);
    429.printf("\n");
    430. 
    431.printf("先序遍历:\n");
    432.Pre_Tree_Walk(T);
    433. 
    434.printf("\n");
    435.}</code>

    2.区间树

    区间树是通过扩张红黑树来构成由区间构成的动态集合。结点的属性由一个关键字key变成了一个区间。 
    \

    1.添加附加信息

    添加区间信息INT,INT结构包含区间的左右端点。还包含Max属性,它是以自身为根的子树中所有的区间的端点最大值。(上图中虚线下方)

    view sourceprint?
    01.<code class=" hljs d">enum colors{red,black};//枚举类型
    02.struct Interval //区间
    03.{
    04.int low;
    05.int high;
    06.};
    07.typedef struct Node
    08.{
    09.struct Node * p;
    10.struct Node *left;
    11.struct Node *right;
    12.enum  colors color;
    13.//添加的属性
    14.struct Interval INT;   //存储结点区间信息                  
    15.int  Max;              //以结点为根的所有区间端点的最大值     
    16.}Node;</code>

    2.修改基本操作

    修改红黑树的插入和删除操作维添加的信息,都能保证在O(lgn)的时间内完成; 
    1.插入操作: 
    第一步:由于区间树采用区间左端点作为关键字进行插入,遍历时通过比较INT.low的方式插入;插入前令Max=high,插入时从根节点开始遍历到要插入的位置,把遍历的结点的Max与新添加的结点z的Max进行比较,如果z.Max>x.Max ,更新结点的x.Max=z.Max

    view sourceprint?
    01.<code class=" hljs lasso">Node *Interval_Insert(Node *Root,Node * z)   //红黑树插入,返回树的根
    02.{
    03.Node * y=T_NIL;
    04.Node * x=Root;
    05.while( x != T_NIL)                 //找到结点z要插入的位置   
    06.{
    07.if ( z->Max > x->Max)     //比较新插入的结点z与结点x的Max大小;
    08.{
    09.x->Max = z->Max;
    10.}
    11.y=x;
    12.if (z->INT.low < x->INT.low)
    13.x = x->left;
    14.else
    15.x = x->right;
    16.}
    17.z->p = y;
    18.if ( y == T_NIL)    //插入第一个结点作为根节点的情况 
    19.Root = z;
    20.else if (z->INT.low < y->INT.low)
    21.y->left = z;
    22.else   
    23.y->right = z;
    24. 
    25.Root = Interval_Insert_Fixup(Root,z);    //插入完毕后,对红黑树的颜色进行修正
    26.return Root;
    27.}</code>

    第二步:由于左旋右旋会破坏区间的性质,在函数代码后添加更新信息

    view sourceprint?
    01.<code class=" hljs lasso">void Left_Rotate(Node **T,Node * x)   //左旋
    02.{
    03.Node *y=x->right;
    04. 
    05.x->right =y->left;
    06.if (y->left != T_NIL)
    07.y->left->p=x;
    08.y->p=x->p;
    09.if(x->p==T_NIL)
    10.*T=y;
    11.else if (x == x->p->left)
    12.x->p->left = y;
    13.else
    14.x->p->right = y;
    15.y->left = x;
    16.x->p=y;
    17. 
    18.y->Max = x->Max;                         //添加语句维护Max
    19.x->Max = GetMax(x->left->Max,x->right->Max,x->INT.high);
    20.}
    21.void Right_Rotate(Node **T,Node * y)   //右旋
    22.{
    23.Node *x=y->left;
    24. 
    25.y->left =x->right;
    26.if (x->right != T_NIL)
    27.x->right->p=y;
    28.x->p=y->p;
    29.if(y->p==T_NIL)
    30.*T=x;
    31.else if (y == y->p->left)
    32.y->p->left = x;
    33.else 
    34.y->p->right = x;
    35.x->right = y;
    36.y->p=x;
    37. 
    38.x->Max = y->Max;                         //添加语句维护Max
    39.y->Max = GetMax(y->left->Max,y->right->Max,y->INT.high);
    40.}</code>

    2.删除操作

    第一步:被删除的结点z可能会影响整个区间树的性质,如果结点z少于两个孩子,则沿着z上升到根节点为止,对树重新更新维护;如果有两个孩子则从后继出发,进行维护;

    view sourceprint?
    1.<code class=" hljs lasso">while( temp != T_NIL )             //从要删除的结点或其后继开始向上修复区间树
    2.{      
    3.temp->Max = GetMax(temp->left->Max,temp->right->Max,temp->INT.high);
    4.temp = temp->p;     //每次一层,至多lgn层
    5.}</code>

    第二步:同上,也是在左旋右旋函数后添加代码。

    3.设计新的操作

    判断给定的一个区间i位于区间树的哪个位置。区间之间的关系: 
    \ 
    a重叠的情况;b、c不重叠的情况 
    不重叠的情况用代码表示为

    view sourceprint?
    1.<code class=" hljs haskell">x->INT.high < i->low
    2.x->INT.low  > i->high</code>

    如果存在区间与i重叠则返回结点的位置,否则返回T_NIL

    view sourceprint?
    01.<code class=" hljs lasso">Node * Interval_Search(Node *T ,struct Interval *i)  //寻找数k是否在树中,且返回数k的地址
    02.{  
    03.Node * x = T;
    04.while(x != T_NIL && ((x->INT.high < i->low)||(x->INT.low > i->high)))  //不重叠
    05.{
    06.if (x->left != T_NIL && x->left->Max >= i->low)  //在其左子树中搜索
    07.{
    08.x = x->left;
    09.}
    10.else
    11.{
    12.x = x->right;
    13.}
    14.}
    15. 
    16.return x;
    17.}</code>

    每次迭代都是一层,至多lgn层;所以耗时O(lgn)的时间

    4.完整代码

    view sourceprint?
    001.<code class=" hljs haskell">/*       
    002.CSDN 勿在浮砂筑高台
    003.http://blog.csdn.net/luoshixian099
    004.算法导论--区间树
    005.2015年5月20日
    006.*/
    007.#include <STDIO.H>
    008.#include <STDLIB.H>
    009.enum colors{red,black};//枚举类型
    010.struct Interval //区间
    011.{
    012.int low;
    013.int high;
    014.};
    015.typedef struct Node
    016.{
    017.struct Node * p;
    018.struct Node *left;
    019.struct Node *right;
    020.enum  colors color;
    021.//添加的属性
    022.struct Interval INT;   //存储结点区间信息                  
    023.int  Max;              //以结点为根的所有区间端点的最大值     
    024.}Node;
    025.Node *T_NIL=NULL;                 //建立全部变量 T_NIL
    026. 
    027.int GetMax(int a,int b,int c)    //返回a,b,c最大值
    028.{
    029.return a>b?(a>c?a:c):(b>c?b:c);
    030.}
    031.Node * Tree_Minimum(Node * T)     //找最小结点
    032.{
    033.while(T->left != T_NIL)
    034.T=T->left;
    035.return T;
    036.}
    037.void Inorder_Tree_Walk(Node * T)  //中序遍历树T,输出
    038.{
    039.if ( T != T_NIL)
    040.{
    041.Inorder_Tree_Walk(T->left);   //递归其左孩子
    042.printf("%d",T->INT.low);        //输出根的关键字
    043.if (T->color == 0)
    044.{
    045.printf("-R(%d)  ",T->Max);
    046.}
    047.else
    048.{
    049.printf("-B(%d)   ",T->Max);
    050.}
    051.Inorder_Tree_Walk(T->right);  //递归其右孩子
    052.}
    053.}
    054.void Pre_Tree_Walk(Node * T)  //
    055.{
    056.if ( T != T_NIL)
    057.{    
    058.printf("%d    ",T->INT.low);          //输出根的关键字
    059.Pre_Tree_Walk(T->left);   //递归其左孩子     
    060.Pre_Tree_Walk(T->right);  //递归其右孩子
    061. 
    062.}
    063.}
    064. 
    065.void Left_Rotate(Node **T,Node * x)   //左旋
    066.{
    067.Node *y=x->right;
    068. 
    069.x->right =y->left;
    070.if (y->left != T_NIL)
    071.y->left->p=x;
    072.y->p=x->p;
    073.if(x->p==T_NIL)
    074.*T=y;
    075.else if (x == x->p->left)
    076.x->p->left = y;
    077.else
    078.x->p->right = y;
    079.y->left = x;
    080.x->p=y;
    081. 
    082.y->Max = x->Max;                         //添加语句维护Max
    083.x->Max = GetMax(x->left->Max,x->right->Max,x->INT.high);
    084.}
    085.void Right_Rotate(Node **T,Node * y)   //右旋
    086.{
    087.Node *x=y->left;
    088. 
    089.y->left =x->right;
    090.if (x->right != T_NIL)
    091.x->right->p=y;
    092.x->p=y->p;
    093.if(y->p==T_NIL)
    094.*T=x;
    095.else if (y == y->p->left)
    096.y->p->left = x;
    097.else 
    098.y->p->right = x;
    099.x->right = y;
    100.y->p=x;
    101. 
    102.x->Max = y->Max;                         //添加语句维护Max
    103.y->Max = GetMax(y->left->Max,y->right->Max,y->INT.high);
    104.}
    105.Node* Interval_Insert_Fixup(Node *T,Node *z)
    106.{
    107.Node * y=NULL;
    108.while( z->p->color == red)       //违反了性质4,迭代进行修正
    109.{
    110.if (z->p == z->p->p->left)
    111.{
    112.y = z->p->p->right;
    113.if ( y->color == red)    // case 1 叔结点为红色
    114.{
    115.z->p->color = black;    //父节点涂黑
    116.y->color = black;       //叔结点涂黑
    117.z->p->p->color = red;   //祖结点涂红
    118.z = z->p->p;            //向上迭代,更新z的位置
    119.}
    120.else if ( z == z->p->right) //case 2 叔结点为黑色且z为双亲的右孩子
    121.{
    122.z = z->p;
    123.Left_Rotate(&T,z);
    124.z->p->color = black;    //case2 已转为 case3 继续处理
    125.z->p->p->color = red;
    126.Right_Rotate(&T,z->p->p);// while循环终止
    127.}
    128.else                      // case 3 叔结点为黑色且z为双亲的左孩子
    129.{
    130.z->p->color = black;
    131.z->p->p->color = red;
    132.Right_Rotate(&T,z->p->p);//   while循环终止
    133.}
    134.}
    135. 
    136.else                      //对称处理
    137.{
    138. 
    139.y = z->p->p->left;
    140.if ( y->color == red)    // case 1 叔结点为红色
    141.{
    142.z->p->color = black;
    143.y->color = black;
    144.z->p->p->color = red;
    145.z = z->p->p;
    146.}
    147. 
    148.else if ( z == z->p->left) //case 2 叔结点为黑色且z为双亲的右孩子
    149.{
    150.z = z->p;
    151.Right_Rotate(&T,z);
    152.z->p->color = black;
    153.z->p->p->color = red;
    154.Left_Rotate(&T,z->p->p);//
    155.}
    156.else                      // case 3
    157.{
    158.z->p->color = black;
    159.z->p->p->color = red;
    160.Left_Rotate(&T,z->p->p);
    161.}
    162. 
    163.
    164.}
    165. 
    166.T->color = black;          //保证不会违反性质2,对根节点涂黑
    167.return T;
    168.}
    169.Node *Interval_Insert(Node *Root,Node * z)   //红黑树插入,返回树的根
    170.{
    171.Node * y=T_NIL;
    172.Node * x=Root;
    173.while( x != T_NIL)                 //找到结点z要插入的位置   
    174.{
    175.if ( z->Max > x->Max)     //比较新插入的结点z与结点x的Max大小;
    176.{
    177.x->Max = z->Max;
    178.}
    179.y=x;
    180.if (z->INT.low < x->INT.low)
    181.x = x->left;
    182.else
    183.x = x->right;
    184.}
    185.z->p = y;
    186.if ( y == T_NIL)    //插入第一个结点作为根节点的情况 
    187.Root = z;
    188.else if (z->INT.low < y->INT.low)
    189.y->left = z;
    190.else   
    191.y->right = z;
    192. 
    193.Root = Interval_Insert_Fixup(Root,z);    //插入完毕后,对红黑树的颜色进行修正
    194.return Root;
    195.}
    196.Node * Establish(int A[][2],int len)   //建立红黑树
    197.{
    198.Node * T,*node;
    199.int i=0;
    200.node=NULL;
    201.T_NIL=(Node *)malloc(sizeof(Node));  //建立T_NIL结点
    202.T_NIL->p=NULL;
    203.T_NIL->left=NULL;
    204.T_NIL->right=NULL;
    205.T_NIL->INT.low=-1;
    206.T_NIL->color=black;
    207.T_NIL->Max=0;
    208.T=T_NIL;
    209.for (i=0;i<len;i++)
    210.{
    211.node =(Node *)malloc(sizeof(Node));
    212.node->p =T_NIL;
    213.node->left=T_NIL;
    214.node->right=T_NIL;
    215.node->INT.low=A[i][0];         //以INT.low左作为关键字
    216.node->INT.high=A[i][1];        
    217.node->Max = A[i][1];          
    218.node->color=red;
    219.T=Interval_Insert(T,node);
    220.}
    221.return T;
    222.}
    223. 
    224.void RB_Transplant(Node **T,Node * u,Node * v)  //结点替代函数
    225.{
    226.if (u->p == T_NIL)
    227.*T = v;
    228.else if (u == u->p->left)
    229.u->p->left = v;
    230.else
    231.u->p->right = v;
    232.v->p = u->p;               //此处赋值无条件,v如果是T_NIL也要进行赋值
    233.}
    234.Node* Interval_Delete_Fixup(Node * T,Node * x)
    235.{
    236.Node *w=NULL;
    237.while( x != T && x->color == black)      //循环迭代处理
    238.{
    239.if ( x == x->p->left )
    240.{
    241.w = x->p->right;
    242.if (w->color == red)             // case 1 ------> case 2 , case 3 ,case 4
    243.{
    244.w->color = black;
    245.x->p->color =red;
    246.Left_Rotate(&T,x->p);
    247.w = x->p->right;
    248.}
    249.if ( w->left->color == black && w->right->color == black ) //case 2 ------>go on / stop
    250.{
    251.w->color = red;
    252.x = x->p;
    253.}
    254.else if ( w->right->color == black)   // case 3 ---->case 4---->stop
    255.{
    256.w->left->color = black;
    257.w->color =red ;
    258.Right_Rotate(&T,w);
    259. 
    260.w = x->p->right ;                   //转成case 4处理
    261.w->color = x->p->color;
    262.x->p->color = black;
    263.w->right->color = black;
    264.Left_Rotate(&T,x->p);
    265.x = T;
    266.}
    267.else                               // case 4 ------------------->stop
    268.{
    269.w->color = x->p->color;
    270.x->p->color = black;
    271.w->right->color = black;
    272.Left_Rotate(&T,x->p);
    273.x = T;
    274.}
    275.}
    276.else
    277.{
    278. 
    279.w = x->p->left;
    280. 
    281.if (w->color == red)                // case 1 ------> case 2 , case 3 ,case 4
    282.{
    283.w->color = black;
    284.x->p->color =red;
    285.Right_Rotate(&T,x->p);
    286.w = x->p->left;
    287.}
    288.if ( w->right->color == black && w->left->color == black ) //case 2 ------>go on/stop
    289.{
    290. 
    291.w->color = red;
    292.x = x->p;
    293.}
    294.else if ( w->left->color == black)      // case 3 -----> case 4----->stop
    295.{
    296.w->right->color = black;
    297.w->color =red ;
    298.Left_Rotate(&T,w);
    299. 
    300.w = x->p->left ;                    //转成case 4处理
    301.w->color = x->p->color;
    302.x->p->color = black;
    303.w->left->color = black;
    304.Right_Rotate(&T,x->p);
    305.x = T;
    306.}
    307.else                                  // case 4 -------------->stop
    308.{
    309.w->color = x->p->color;
    310.x->p->color = black;
    311.w->left->color = black;
    312.Right_Rotate(&T,x->p);
    313.x = T;
    314.}
    315.}
    316.}
    317. 
    318.x->color = black;                       //可能由case2退出,那把x涂黑即可,见分析!也可能有case4退出,把根节点涂黑
    319.return T;
    320.}
    321.Node * Interval_Delete(Node *T ,Node *z)
    322.{
    323. 
    324.Node * x =NULL;
    325.Node * y =z;
    326.Node * temp = y->p;
    327.enum colors y_original_color = y->color;   //记录下删除前z的颜色
    328.if ( z->left == T_NIL)                     //左子树不存在的情况 
    329.{  
    330.x = z->right;
    331.RB_Transplant(&T,z,z->right);
    332. 
    333. 
    334.}
    335.else if ( z->right == T_NIL)              //右子树不存在
    336.{
    337.x = z->left;
    338.RB_Transplant(&T,z,z->left);
    339. 
    340. 
    341.}
    342.else                                     //左右都存在的情况
    343.{
    344.y = Tree_Minimum(z->right);            //找到后继y
    345.temp = y->p;
    346.y_original_color = y->color;           //记录下y转移前的颜色
    347.x = y->right;
    348.if ( y->p == z)                       //如果y是z的子结点
    349.{
    350.x->p = y;
    351.}
    352.else
    353.{
    354.RB_Transplant(&T,y,y->right);    //如果y不是z的子结点,用y的右子树代替y的位置
    355.y->right = z->right;
    356.y->right->p = y;
    357.}
    358.RB_Transplant(&T,z,y);           //y替代z的位置 ,不论y是不是T_NIL  
    359.y->left = z->left;
    360.y->left->p = y;
    361.y->color = z->color;             //把y的颜色改成z的颜色  
    362.}
    363. 
    364.while( temp != T_NIL )             //从要删除的结点或其后继开始向上修复红黑树
    365.{      
    366.temp->Max = GetMax(temp->left->Max,temp->right->Max,temp->INT.high);
    367.temp = temp->p;    
    368.}
    369. 
    370. 
    371.if ( y_original_color == black)   //判断y的颜色,若为黑色,需要修复
    372.T=Interval_Delete_Fixup(T,x);
    373. 
    374.return T;
    375.}
    376. 
    377.Node * Tree_Search(Node *T ,int k)  //寻找数k是否在树中,且返回数k的地址
    378.{  
    379. 
    380.while(T != T_NIL && T->INT.low != k)
    381.{
    382.if ( k < T->INT.low)
    383.T=T->left;
    384.else
    385.T=T->right;
    386.}
    387. 
    388.if ( T == T_NIL)
    389.{    
    390.return NULL;
    391.}
    392. 
    393.else
    394.{
    395.return T;
    396.}
    397. 
    398.}
    399.Node * Interval_Search(Node *T ,struct Interval *i)  //寻找数k是否在树中,且返回数k的地址
    400.{  
    401.Node * x = T;
    402.while(x != T_NIL && ((x->INT.high < i->low)||(x->INT.low > i->high)))  //不重叠
    403.{
    404.if (x->left != T_NIL && x->left->Max >= i->low)  //在其左子树中搜索
    405.{
    406.x = x->left;
    407.}
    408.else
    409.{
    410.x = x->right;
    411.}
    412.}
    413. 
    414.return x;
    415.}
    416.void main()
    417.{
    418.int A[][2]={0,3,                   //区间
    419.5,8,
    420.6,10,
    421.8,9,
    422.15,23,
    423.16,21,
    424.17,19,
    425.19,20,
    426.25,30,
    427.26,26};
    428. 
    429.int length = sizeof(A)/sizeof(A[0]); //数组区间的长度
    430.Node *T,*temp;
    431.struct Interval i;
    432.i.low = 22;
    433.i.high = 25;
    434. 
    435.T=Establish(A,length);        //建立红黑树,返回根节点T
    436.printf("中序遍历:\n");
    437.Inorder_Tree_Walk(T);printf("\n");   //中序遍历输出
    438.printf("-----------删除操作后-------------\n");  
    439.T=Interval_Delete(T,Tree_Search(T,6));
    440.printf("中序遍历:\n");
    441.Inorder_Tree_Walk(T);
    442.printf("\n");
    443. 
    444.temp = Interval_Search(T,&i);
    445.printf("____%d___%d__", temp->INT.low,temp->INT.high);
    446. 
    447.}</code>

延伸阅读:

  • 1、C语言算法导论之平衡二叉树
  • 2、算法导论之平衡二叉树
  • 3、算法导论之平衡二叉树-删除[C语言]
  • 4、C++快速排序实现(quicksort)(算法导论)
  • 5、c++堆排序实现(heapsort)(算法导论)
  • 6、矩阵链乘法 【算法导论】
  • 7、算法导论实验5贪心 活动安排问题与背包问题
  • 8、算法导论学习23 两个单链表(singlelinked)求交点
0 0