您的位置:首页 > 其它

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

2015-05-20 15:00 260 查看
本文的基础是红黑树 算法导论–红黑树

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

1.动态顺序统计

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

1 添加附加信息

结点x中加入x.size , size的大小为以x为根的子树(包含x本身)的内结数,即子树的大小。我们定义哨兵的size为0,如下图:





结点内,虚线上方为关键字key,下方为结点的size。

可以看出: x.size = x.left.size + x.right.size +1;

enum colors{red,black};//枚举类型
typedef struct Node
{
   struct Node * p;
   struct Node *left;
   struct Node *right;
   int key;             
   enum  colors color;  //颜色属性
   int size;           //新添加的属性size
}Node;


2 修改基本操作

插入操作:

为了对子树规模的维护,需要在不影响插入和删除操作的渐进运行时间的前提下,修改基本的操作。

第一阶段:新节点的插入过程中,需要对从根到将要插入的位置过程中遍历的结点的size加1;

第二阶段:维护红黑树的左旋和右旋函数需要在最后添加以下语句:



/*左旋*/
    y.size = x.size;
    x.size = x.left.size + x.right.size +1;
 /*右旋*/
    x.size = y.size;
    y.size = y.left.size + y.right.size +1;


删除操作:

第一阶段:如果要删除的结点z少于两个孩子,则从z到根T的过程遍历的结点size减1;如果要删除的结点z多于两个孩子,则从z的后继y处向上到T的过程中,遍历的结点size减1;

第二阶段:

也是同样在左右旋过程中,添加以上的语句;

插入操作和删除操作运行时间都是O(lgn).

3 设计新的操作

1.给定秩的元素的检索

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

Node * OS_Select(Node *x,int i)
{
    int r =x->left->size+1;           //计算以结点x为根的子树中顺序统计量r
    if (i == r)
        return x;   
    else if (i < r)                
        return OS_Select(x->left,i);  //在x的左子树里继续递归查找
    else
        return OS_Select(x->right,i-r);//在x的右子树里继续递归查找
}


2.确定一个元素的秩

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

int OS_Rank(Node *T,Node * x)
{
    int r =x->left->size+1;  //计算以结点x为根的子树中顺序统计量r
    Node * y =x;
    while(y != T)                 //叠加到root根节点位置
    {
        if (y == y->p->right)          //父节点的右子树输出在左子树和根之后,顺序统计量叠加
        {
            r=r+y->p->left->size+1;
        }
        y = y->p;                      //若属于左子树,直接跳向上层
    }
    return r;
}


4 完整代码

/*        
CSDN 勿在浮砂筑高台 http://blog.csdn.net/luoshixian099 算法导论--顺序统计量
2015年5月20日
*/
#include <STDIO.H> 
#include <STDLIB.H>
enum colors{red,black};//枚举类型
typedef struct Node
{
   struct Node * p;
   struct Node *left;
   struct Node *right;
   int key;
   enum  colors color;
   int size;                       //添加附加信息size
}Node;
Node *T_NIL=NULL;                 //建立全部变量 T_NIL

Node * Tree_Minimum(Node * T)     //找最小结点
{
    while(T->left != T_NIL)
        T=T->left;
    return T;
}
void Inorder_Tree_Walk(Node * T)  //中序遍历树T,输出
{
    if ( T != T_NIL)
    {
        Inorder_Tree_Walk(T->left);   //递归其左孩子
        printf("%d",T->key);        //输出根的关键字
        if (T->color == 0)
        {
            printf("-R");
        }
        else
        {
            printf("-B");
        }
        printf("-(%d)  ",T->size);
        Inorder_Tree_Walk(T->right);  //递归其右孩子
    }
}
void Pre_Tree_Walk(Node * T)  //
{
    if ( T != T_NIL)
    {     
        printf("%d    ",T->key);          //输出根的关键字
        Pre_Tree_Walk(T->left);   //递归其左孩子      
        Pre_Tree_Walk(T->right);  //递归其右孩子

    }
}

void Left_Rotate(Node **T,Node * x)   //左旋
{
   Node *y=x->right;

   x->right =y->left;
   if (y->left != T_NIL)
       y->left->p=x;
   y->p=x->p;
   if(x->p==T_NIL)
      *T=y;
   else if (x == x->p->left)
      x->p->left = y;
   else
      x->p->right = y;
   y->left = x;
   x->p=y;

   y->size = x->size;                         //添加语句维护size
   x->size = x->left->size+x->right->size+1;
}
void Right_Rotate(Node **T,Node * y)   //右旋
{
    Node *x=y->left;

    y->left =x->right;
    if (x->right != T_NIL)
        x->right->p=y;
    x->p=y->p;
    if(y->p==T_NIL)
        *T=x;
    else if (y == y->p->left)
        y->p->left = x;
    else  
        y->p->right = x;
    x->right = y;
    y->p=x;

   x->size = y->size;                     //添加语句维护size
   y->size = y->left->size+y->right->size+1;
}
Node* RB_Insert_Fixup(Node *T,Node *z)
{
    Node * y=NULL;
   while( z->p->color == red)       //违反了性质4,迭代进行修正
   {
      if (z->p == z->p->p->left)
      {
          y = z->p->p->right;
          if ( y->color == red)    // case 1 叔结点为红色
          {
             z->p->color = black;    //父节点涂黑
             y->color = black;       //叔结点涂黑
             z->p->p->color = red;   //祖结点涂红
             z = z->p->p;            //向上迭代,更新z的位置
          }
          else if ( z == z->p->right) //case 2 叔结点为黑色且z为双亲的右孩子
          {
             z = z->p;
             Left_Rotate(&T,z);
             z->p->color = black;    //case2 已转为 case3 继续处理
             z->p->p->color = red;
             Right_Rotate(&T,z->p->p);// while循环终止
          }
          else                      // case 3 叔结点为黑色且z为双亲的左孩子 
          {
             z->p->color = black;
             z->p->p->color = red;
             Right_Rotate(&T,z->p->p);//   while循环终止 
          }
      }

      else                      //对称处理
      {

          y = z->p->p->left;
          if ( y->color == red)    // case 1 叔结点为红色
          {
              z->p->color = black;
              y->color = black;
              z->p->p->color = red;
              z = z->p->p;
          }

          else if ( z == z->p->left) //case 2 叔结点为黑色且z为双亲的右孩子
          {
              z = z->p;
              Right_Rotate(&T,z);
              z->p->color = black;
              z->p->p->color = red;
              Left_Rotate(&T,z->p->p);// 
          }
          else                      // case 3
          {
              z->p->color = black;
              z->p->p->color = red;
              Left_Rotate(&T,z->p->p); 
          }

      }  
   }

   T->color = black;          //保证不会违反性质2,对根节点涂黑
   return T;
}
Node *RB_Insert(Node *Root,Node * z)   //红黑树插入,返回树的根
{
    Node * y=T_NIL;
    Node * x=Root;
    while( x != T_NIL)                 //找到结点z要插入的位置    
    {
        x->size+=1;                    //插入过程中,遍历的结点size加1

        y=x;
        if (z->key < x->key)
            x = x->left;
        else
            x = x->right;
    }
    z->p = y;
    if ( y == T_NIL)    //插入第一个结点作为根节点的情况  
        Root = z;
    else if (z->key < y->key)
        y->left = z;
    else    
        y->right = z;

    Root = RB_Insert_Fixup(Root,z);    //插入完毕后,对红黑树的颜色进行修正
    return Root; 
}
Node * Establish(int *A,int len)   //建立红黑树
{
   Node * T,*node;
   int i=0;
   node=NULL;
   T_NIL=(Node *)malloc(sizeof(Node));  //建立T_NIL结点
   T_NIL->p=NULL;
   T_NIL->left=NULL;
   T_NIL->right=NULL;
   T_NIL->key=-1;
   T_NIL->color=black;
   T_NIL->size=0;
   T=T_NIL;
   for (i=0;i<len;i++)
   {
       node =(Node *)malloc(sizeof(Node));
       node->p =T_NIL;
       node->left=T_NIL;
       node->right=T_NIL;
       node->key=A[i];
       node->color=red;
       node->size=1;
       T=RB_Insert(T,node);
   }
   return T;
}

void RB_Transplant(Node **T,Node * u,Node * v)  //结点替代函数
{
  if (u->p == T_NIL)
      *T = v;
  else if (u == u->p->left)
     u->p->left = v;
  else
     u->p->right = v;
  v->p = u->p;               //此处赋值无条件,v如果是T_NIL也要进行赋值
}
void RB_Delete_Fixup(Node * T,Node * x)
{
    Node *w=NULL;
  while( x != T && x->color == black)      //循环迭代处理
  {
      if ( x == x->p->left )
      {
        w = x->p->right;
        if (w->color == red)             // case 1 ------> case 2 , case 3 ,case 4 
        {
            w->color = black;
            x->p->color =red;
            Left_Rotate(&T,x->p);
            w = x->p->right;
        }
        if ( w->left->color == black && w->right->color == black ) //case 2 ------>go on / stop
        {
            w->color = red;
            x = x->p;
        }
        else if ( w->right->color == black)   // case 3 ---->case 4---->stop
        {
           w->left->color = black;
           w->color =red ;
           Right_Rotate(&T,w);

           w = x->p->right ;                   //转成case 4处理 
           w->color = x->p->color;
           x->p->color = black;
           w->right->color = black;
           Left_Rotate(&T,x->p);
           x = T;
        }
        else                               // case 4 ------------------->stop
        {
            w->color = x->p->color;
            x->p->color = black;
            w->right->color = black;
            Left_Rotate(&T,x->p);
            x = T;
        }
      }
      else
      {
          w = x->p->left;
          if (w->color == red)                // case 1 ------> case 2 , case 3 ,case 4 
          {
              w->color = black;
              x->p->color =red;
              Right_Rotate(&T,x->p);
              w = x->p->left;
          }
          if ( w->right->color == black && w->left->color == black ) //case 2 ------>go on/stop
          {
              w->color = red;
              x = x->p;
          }
          else if ( w->left->color == black)      // case 3 -----> case 4----->stop
          {
              w->right->color = black;
              w->color =red ;
              Left_Rotate(&T,w);

              w = x->p->left ;                    //转成case 4处理
              w->color = x->p->color;
              x->p->color = black;
              w->left->color = black;
              Right_Rotate(&T,x->p);
              x = T;
          }
          else                                  // case 4 -------------->stop
          {
              w->color = x->p->color;
              x->p->color = black;
              w->left->color = black;
              Right_Rotate(&T,x->p);
              x = T;
        }
      }
  }

  x->color = black;                       //可能由case2退出,那把x涂黑即可,见分析!也可能有case4退出,把根节点涂黑
}
Node * RB_Delete(Node *T ,Node *z)
{

    Node * x =NULL;
    Node * y =z;
    Node *temp=y->p;
    enum colors y_original_color = y->color;   //记录下删除前z的颜色
    if ( z->left == T_NIL)                     //左子树不存在的情况  
    {
        x = z->right;
        RB_Transplant(&T,z,z->right);
    }
    else if ( z->right == T_NIL)              //右子树不存在
    {
       x = z->left;
       RB_Transplant(&T,z,z->left);
    }
    else                                     //左右都存在的情况
    {
       y = Tree_Minimum(z->right);            //找到后继y
       temp=y->p;   
       y_original_color = y->color;           //记录下y转移前的颜色
       x = y->right;
       if ( y->p == z)                       //如果y是z的子结点
       {
         x->p = y;
       }
       else
       {
           RB_Transplant(&T,y,y->right);    //如果y不是z的子结点,用y的右子树代替y的位置
           y->right = z->right;
           y->right->p = y;
       }
       RB_Transplant(&T,z,y);           //y替代z的位置 ,不论y是不是T_NIL   
       y->left = z->left;
       y->left->p = y;
       y->color = z->color;             //把y的颜色改成z的颜色

       y->size =y->left->size+y->right->size+1;
    }

     while(temp != T_NIL)             //从删除的位置或后继的位置向上遍历size--,直到根节点为止
        {
            temp->size--;
            temp = temp->p;
        }

    if ( y_original_color == black)   //判断y的颜色,若为黑色,需要修复
        RB_Delete_Fixup(T,x);
    return T;
}

Node * Tree_Search(Node *T ,int k)  //寻找数k是否在树中,且返回数k的地址
{   

    while(T !=T_NIL && T->key != k)
    {
        if ( k < T->key)
            T=T->left;
        else
            T=T->right;
    }

    if ( T == T_NIL)
    {     
        return NULL;
    }

    else 
    {
        return T;
    }

}
Node * OS_Select(Node *x,int i)        //确定以x为根节点的子树,第i小的关键字
{
    int r =x->left->size+1;
    if (i == r)
        return x;   
    else if (i < r)
        return OS_Select(x->left,i);
    else
        return OS_Select(x->right,i-r);
}
int OS_Rank(Node *T,Node * x)         //确定x在树T中序遍历中的位置顺序
{
    int r =x->left->size+1;
    Node * y =x;
    while(y != T)
    {
        if (y == y->p->right)
        {
            r=r+y->p->left->size+1;
        }
        y = y->p;
    }
    return r;
}
void main()
{
    int A[]={2,5,1,6,3,8,4,9,7};

    int length = sizeof(A)/sizeof(A[0]); //数组A的长度
    Node *T =Establish(A,length);        //建立红黑树,返回根节点T

    printf("中序遍历:\n");
    Inorder_Tree_Walk(T);printf("\n");   //中序遍历输出

    printf("先序遍历:\n");              //先序遍历输出
    Pre_Tree_Walk(T);printf("\n");

    printf("__%d__\n",OS_Select(T,5)->key);
    printf("--%d--\n",OS_Rank(T,Tree_Search(T,3)));

    printf("-----------删除操作后-------------\n");

    T=RB_Delete(T,Tree_Search(T,2));
    T=RB_Delete(T,Tree_Search(T,5));
    T=RB_Delete(T,Tree_Search(T,7));
    T=RB_Delete(T,Tree_Search(T,4));
    printf("中序遍历:\n");
    Inorder_Tree_Walk(T);
    printf("\n");

    printf("先序遍历:\n");
    Pre_Tree_Walk(T);

    printf("\n");
}


2.区间树

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



1.添加附加信息

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

enum colors{red,black};//枚举类型
struct Interval //区间
{
    int low;
    int high;
};
typedef struct Node
{
   struct Node * p;
   struct Node *left;
   struct Node *right;
   enum  colors color;
   //添加的属性
   struct Interval INT;   //存储结点区间信息                   
   int  Max;              //以结点为根的所有区间端点的最大值      
}Node;


2.修改基本操作

修改红黑树的插入和删除操作维添加的信息,都能保证在O(lgn)的时间内完成;

1.插入操作

第一步:由于区间树采用区间左端点作为关键字进行插入,遍历时通过比较INT.low的方式插入;插入前令Max=high,插入时从根节点开始遍历到要插入的位置,把遍历的结点的Max与新添加的结点z的Max进行比较,如果z.Max>x.Max ,更新结点的x.Max=z.Max

Node *Interval_Insert(Node *Root,Node * z)   //红黑树插入,返回树的根
{
    Node * y=T_NIL;
    Node * x=Root;
    while( x != T_NIL)                 //找到结点z要插入的位置    
    {
        if ( z->Max > x->Max)     //比较新插入的结点z与结点x的Max大小;
        {
            x->Max = z->Max;
        }
        y=x;
        if (z->INT.low < x->INT.low)
            x = x->left;
        else
            x = x->right;
    }
    z->p = y;
    if ( y == T_NIL)    //插入第一个结点作为根节点的情况  
        Root = z;
    else if (z->INT.low < y->INT.low)
        y->left = z;
    else    
        y->right = z;

    Root = Interval_Insert_Fixup(Root,z);    //插入完毕后,对红黑树的颜色进行修正
    return Root; 
}


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

void Left_Rotate(Node **T,Node * x)   //左旋
{
   Node *y=x->right;

   x->right =y->left;
   if (y->left != T_NIL)
       y->left->p=x;
   y->p=x->p;
   if(x->p==T_NIL)
      *T=y;
   else if (x == x->p->left)
      x->p->left = y;
   else
      x->p->right = y;
   y->left = x;
   x->p=y;

  y->Max = x->Max;                         //添加语句维护Max
  x->Max = GetMax(x->left->Max,x->right->Max,x->INT.high);
}
void Right_Rotate(Node **T,Node * y)   //右旋
{
    Node *x=y->left;

    y->left =x->right;
    if (x->right != T_NIL)
        x->right->p=y;
    x->p=y->p;
    if(y->p==T_NIL)
        *T=x;
    else if (y == y->p->left)
        y->p->left = x;
    else  
        y->p->right = x;
    x->right = y;
    y->p=x;

  x->Max = y->Max;                         //添加语句维护Max
  y->Max = GetMax(y->left->Max,y->right->Max,y->INT.high);
}


2.删除操作

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

while( temp != T_NIL )             //从要删除的结点或其后继开始向上修复区间树
    {       
            temp->Max = GetMax(temp->left->Max,temp->right->Max,temp->INT.high);
            temp = temp->p;     //每次一层,至多lgn层
    }


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

3.设计新的操作

判断给定的一个区间i位于区间树的哪个位置。区间之间的关系:




a重叠的情况;b、c不重叠的情况

不重叠的情况用代码表示为

x->INT.high < i->low
x->INT.low  > i->high


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

Node * Interval_Search(Node *T ,struct Interval *i)  //寻找数k是否在树中,且返回数k的地址
{   
    Node * x = T;
    while(x != T_NIL && ((x->INT.high < i->low)||(x->INT.low > i->high)))  //不重叠
    {
        if (x->left != T_NIL && x->left->Max >= i->low)  //在其左子树中搜索
        {
            x = x->left;
        }
        else
        {
            x = x->right;
        }
    }

    return x;
}


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

4.完整代码

/*        
CSDN 勿在浮砂筑高台 http://blog.csdn.net/luoshixian099 算法导论--区间树
2015年5月20日
*/
#include <STDIO.H>
#include <STDLIB.H>
enum colors{red,black};//枚举类型 struct Interval //区间 { int low; int high; }; typedef struct Node { struct Node * p; struct Node *left; struct Node *right; enum colors color; //添加的属性 struct Interval INT; //存储结点区间信息 int Max; //以结点为根的所有区间端点的最大值 }Node;
Node *T_NIL=NULL; //建立全部变量 T_NIL

int GetMax(int a,int b,int c) //返回a,b,c最大值
{
return a>b?(a>c?a:c):(b>c?b:c);
}
Node * Tree_Minimum(Node * T) //找最小结点
{
while(T->left != T_NIL)
T=T->left;
return T;
}
void Inorder_Tree_Walk(Node * T) //中序遍历树T,输出
{
if ( T != T_NIL)
{
Inorder_Tree_Walk(T->left); //递归其左孩子
printf("%d",T->INT.low); //输出根的关键字
if (T->color == 0)
{
printf("-R(%d) ",T->Max);
}
else
{
printf("-B(%d) ",T->Max);
}
Inorder_Tree_Walk(T->right); //递归其右孩子
}
}
void Pre_Tree_Walk(Node * T) //
{
if ( T != T_NIL)
{
printf("%d ",T->INT.low); //输出根的关键字
Pre_Tree_Walk(T->left); //递归其左孩子
Pre_Tree_Walk(T->right); //递归其右孩子

}
}

void Left_Rotate(Node **T,Node * x) //左旋 { Node *y=x->right; x->right =y->left; if (y->left != T_NIL) y->left->p=x; y->p=x->p; if(x->p==T_NIL) *T=y; else if (x == x->p->left) x->p->left = y; else x->p->right = y; y->left = x; x->p=y; y->Max = x->Max; //添加语句维护Max x->Max = GetMax(x->left->Max,x->right->Max,x->INT.high); } void Right_Rotate(Node **T,Node * y) //右旋 { Node *x=y->left; y->left =x->right; if (x->right != T_NIL) x->right->p=y; x->p=y->p; if(y->p==T_NIL) *T=x; else if (y == y->p->left) y->p->left = x; else y->p->right = x; x->right = y; y->p=x; x->Max = y->Max; //添加语句维护Max y->Max = GetMax(y->left->Max,y->right->Max,y->INT.high); }
Node* Interval_Insert_Fixup(Node *T,Node *z)
{
Node * y=NULL;
while( z->p->color == red) //违反了性质4,迭代进行修正
{
if (z->p == z->p->p->left)
{
y = z->p->p->right;
if ( y->color == red) // case 1 叔结点为红色
{
z->p->color = black; //父节点涂黑
y->color = black; //叔结点涂黑
z->p->p->color = red; //祖结点涂红
z = z->p->p; //向上迭代,更新z的位置
}
else if ( z == z->p->right) //case 2 叔结点为黑色且z为双亲的右孩子
{
z = z->p;
Left_Rotate(&T,z);
z->p->color = black; //case2 已转为 case3 继续处理
z->p->p->color = red;
Right_Rotate(&T,z->p->p);// while循环终止
}
else // case 3 叔结点为黑色且z为双亲的左孩子
{
z->p->color = black;
z->p->p->color = red;
Right_Rotate(&T,z->p->p);// while循环终止
}
}

else //对称处理
{

y = z->p->p->left;
if ( y->color == red) // case 1 叔结点为红色
{
z->p->color = black;
y->color = black;
z->p->p->color = red;
z = z->p->p;
}

else if ( z == z->p->left) //case 2 叔结点为黑色且z为双亲的右孩子
{
z = z->p;
Right_Rotate(&T,z);
z->p->color = black;
z->p->p->color = red;
Left_Rotate(&T,z->p->p);//
}
else // case 3
{
z->p->color = black;
z->p->p->color = red;
Left_Rotate(&T,z->p->p);
}

}
}

T->color = black; //保证不会违反性质2,对根节点涂黑
return T;
}
Node *Interval_Insert(Node *Root,Node * z) //红黑树插入,返回树的根 { Node * y=T_NIL; Node * x=Root; while( x != T_NIL) //找到结点z要插入的位置 { if ( z->Max > x->Max) //比较新插入的结点z与结点x的Max大小; { x->Max = z->Max; } y=x; if (z->INT.low < x->INT.low) x = x->left; else x = x->right; } z->p = y; if ( y == T_NIL) //插入第一个结点作为根节点的情况 Root = z; else if (z->INT.low < y->INT.low) y->left = z; else y->right = z; Root = Interval_Insert_Fixup(Root,z); //插入完毕后,对红黑树的颜色进行修正 return Root; }
Node * Establish(int A[][2],int len) //建立红黑树
{
Node * T,*node;
int i=0;
node=NULL;
T_NIL=(Node *)malloc(sizeof(Node)); //建立T_NIL结点
T_NIL->p=NULL;
T_NIL->left=NULL;
T_NIL->right=NULL;
T_NIL->INT.low=-1;
T_NIL->color=black;
T_NIL->Max=0;
T=T_NIL;
for (i=0;i<len;i++)
{
node =(Node *)malloc(sizeof(Node));
node->p =T_NIL;
node->left=T_NIL;
node->right=T_NIL;
node->INT.low=A[i][0]; //以INT.low左作为关键字
node->INT.high=A[i][1];
node->Max = A[i][1];
node->color=red;
T=Interval_Insert(T,node);
}
return T;
}

void RB_Transplant(Node **T,Node * u,Node * v) //结点替代函数
{
if (u->p == T_NIL)
*T = v;
else if (u == u->p->left)
u->p->left = v;
else
u->p->right = v;
v->p = u->p; //此处赋值无条件,v如果是T_NIL也要进行赋值
}
Node* Interval_Delete_Fixup(Node * T,Node * x)
{
Node *w=NULL;
while( x != T && x->color == black) //循环迭代处理
{
if ( x == x->p->left )
{
w = x->p->right;
if (w->color == red) // case 1 ------> case 2 , case 3 ,case 4
{
w->color = black;
x->p->color =red;
Left_Rotate(&T,x->p);
w = x->p->right;
}
if ( w->left->color == black && w->right->color == black ) //case 2 ------>go on / stop
{
w->color = red;
x = x->p;
}
else if ( w->right->color == black) // case 3 ---->case 4---->stop
{
w->left->color = black;
w->color =red ;
Right_Rotate(&T,w);

w = x->p->right ; //转成case 4处理
w->color = x->p->color;
x->p->color = black;
w->right->color = black;
Left_Rotate(&T,x->p);
x = T;
}
else // case 4 ------------------->stop
{
w->color = x->p->color;
x->p->color = black;
w->right->color = black;
Left_Rotate(&T,x->p);
x = T;
}
}
else
{

w = x->p->left;

if (w->color == red) // case 1 ------> case 2 , case 3 ,case 4
{
w->color = black;
x->p->color =red;
Right_Rotate(&T,x->p);
w = x->p->left;
}
if ( w->right->color == black && w->left->color == black ) //case 2 ------>go on/stop
{

w->color = red;
x = x->p;
}
else if ( w->left->color == black) // case 3 -----> case 4----->stop
{
w->right->color = black;
w->color =red ;
Left_Rotate(&T,w);

w = x->p->left ; //转成case 4处理
w->color = x->p->color;
x->p->color = black;
w->left->color = black;
Right_Rotate(&T,x->p);
x = T;
}
else // case 4 -------------->stop
{
w->color = x->p->color;
x->p->color = black;
w->left->color = black;
Right_Rotate(&T,x->p);
x = T;
}
}
}

x->color = black; //可能由case2退出,那把x涂黑即可,见分析!也可能有case4退出,把根节点涂黑
return T;
}
Node * Interval_Delete(Node *T ,Node *z)
{

Node * x =NULL;
Node * y =z;
Node * temp = y->p;
enum colors y_original_color = y->color; //记录下删除前z的颜色
if ( z->left == T_NIL) //左子树不存在的情况
{
x = z->right;
RB_Transplant(&T,z,z->right);

}
else if ( z->right == T_NIL) //右子树不存在
{
x = z->left;
RB_Transplant(&T,z,z->left);

}
else //左右都存在的情况
{
y = Tree_Minimum(z->right); //找到后继y
temp = y->p;
y_original_color = y->color; //记录下y转移前的颜色
x = y->right;
if ( y->p == z) //如果y是z的子结点
{
x->p = y;
}
else
{
RB_Transplant(&T,y,y->right); //如果y不是z的子结点,用y的右子树代替y的位置
y->right = z->right;
y->right->p = y;
}
RB_Transplant(&T,z,y); //y替代z的位置 ,不论y是不是T_NIL
y->left = z->left;
y->left->p = y;
y->color = z->color; //把y的颜色改成z的颜色
}

while( temp != T_NIL ) //从要删除的结点或其后继开始向上修复红黑树
{
temp->Max = GetMax(temp->left->Max,temp->right->Max,temp->INT.high);
temp = temp->p;
}

if ( y_original_color == black) //判断y的颜色,若为黑色,需要修复
T=Interval_Delete_Fixup(T,x);

return T;
}

Node * Tree_Search(Node *T ,int k) //寻找数k是否在树中,且返回数k的地址
{

while(T != T_NIL && T->INT.low != k)
{
if ( k < T->INT.low)
T=T->left;
else
T=T->right;
}

if ( T == T_NIL)
{
return NULL;
}

else
{
return T;
}

}
Node * Interval_Search(Node *T ,struct Interval *i) //寻找数k是否在树中,且返回数k的地址 { Node * x = T; while(x != T_NIL && ((x->INT.high < i->low)||(x->INT.low > i->high))) //不重叠 { if (x->left != T_NIL && x->left->Max >= i->low) //在其左子树中搜索 { x = x->left; } else { x = x->right; } } return x; }
void main()
{
int A[][2]={0,3, //区间
5,8,
6,10,
8,9,
15,23,
16,21,
17,19,
19,20,
25,30,
26,26};

int length = sizeof(A)/sizeof(A[0]); //数组区间的长度
Node *T,*temp;
struct Interval i;
i.low = 22;
i.high = 25;

T=Establish(A,length); //建立红黑树,返回根节点T
printf("中序遍历:\n");
Inorder_Tree_Walk(T);printf("\n"); //中序遍历输出
printf("-----------删除操作后-------------\n");
T=Interval_Delete(T,Tree_Search(T,6));
printf("中序遍历:\n");
Inorder_Tree_Walk(T);
printf("\n");

temp = Interval_Search(T,&i);
printf("____%d___%d__", temp->INT.low,temp->INT.high);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: