RBTree

原文地址:http://blog.sina.com.cn/s/blog_60707c0f01011zz1.html

0 定义

    红黑树是一棵二叉查找树,树中的结点分为外结点和内结点,外结点本质就是一个NIL空指针叶结点,我们一般把外结点忽略画出来,内结点用来存储关键字。结点新增一个颜色域为红色或黑色,满足下列性质:
①每个结点一定是红色或者黑色;
②根结点一定是黑色的;
③每个外结点也是黑色的;
④如果一个内结点是红的,那么两个儿子都是黑色的;
⑤从任意一个内结点出发,到其子孙任意外结点的所有路径的黑结点都相等;
其中⑤决定了具有n个内结点的红黑树的高度不会超过2lg(n+1),与AVL相比,在复杂度上几乎是一样的,但是它没有AVL那么讲究平衡性能,但是在旋转操作的次数(最多两次)上比AVL的最坏的平均性能要好很多,如下图就是一棵红黑树:

RBTree

红黑树的本质实际上是一棵2-3-4树的变形,如上图中的红黑树等同于下图中的B树:
RBTree

1 旋转

 旋转的操作与AVL大同小异,分为左旋转和右旋转两种情况,比较简单,这里就不详说了,C++代码如下:

//Created by pritry

#define RB_RED 0

#define RB_BLACK 1

struct rb_tree

{

  int color;

  int key;

  rb_tree* lchild;

  rb_tree* rchild;

  rb_tree* parent;   //父指针

};


void rb_rotate_left(rb_tree** T, rb_tree* node)

{

  rb_tree* r = node->rchild;

  node->rchild = r->lchild;


  if(r->lchild) 

    r->lchild->parent = node;


  r->parent = node->parent;


  if(node->parent == NULL)

    *T = r;

  else if(node->parent->lchild == node)

    node->parent->lchild = r;

  else

    node->parent->rchild = r;

 

  r->lchild = node;


  node->parent = r;

}


void rb_rotate_right(rb_tree** T, rb_tree* node)

{

  rb_tree* l = node->lchild;

  node->lchild = l->rchild;


  if(l->rchild) 

    l->rchild->parent = node;


  l->parent = node->parent;


  if(node->parent == NULL)

    *T = l;

  else if(node->parent->lchild == node)

    node->parent->lchild = l;

  else

    node->parent->rchild = l;


  l->rchild = node;


  node->parent = l;

}

2 插入

插入的方法与二叉排序树一样,最后染色为红色,然后进行分对称的三种情况来进行调节结点颜色,旋转次数不超过两次,这比AVL显然好很多。①node的叔叔是红色;②node的叔叔是黑色,且node是爸爸的右孩子;③node的叔叔是黑色,且node是爸爸的左孩子,由于对称性我们引入一个依次插入{12,10,8,6,7}的例子来构造红黑树,插入12后结点的12为黑色且为根结点,如下所示:

RBTree
插入结点10,结点10为红色,无需旋转和染色,如下所示:
RBTree
插入结点8,结点8为红色,结点8和结点10为红色,8的叔叔为外结点属于黑色,且8为10的左孩子,属于③,则只需右旋一次,再对根结点10染黑即可,如下所示:
RBTree

RBTree
RBTree
插入结点6,结点6为红色,结点6和结点8为红色,6的叔叔为12属于红色,且6为8的左孩子,属于①,则需要对叔叔12和父亲8染黑,爷爷2染红,现对根结点10染黑即可,如下所示:
RBTree
RBTree
RBTree
插入结点7,结点7为红色,结点7的叔叔为黑色外结点,且结点7为爸爸6的右孩子,属于②,则需对爸爸6先进行左旋转一次,再对结点7右旋转一次,对结点7进行染黑,对爷爷8染红,最后对根结点染黑,如下所示:
RBTree
RBTree
RBTree
RBTree

C++代码如下:

//Created by pritry

void rb_insert_node(rb_tree** T, rb_tree* node)

{

  rb_tree* p = NULL;

  rb_tree* q = *T;


  while(q)

  {

    p = q;


    if(node->key < q->key)

      q = q->lchild;

    else

      q = q->rchild;

  }


  node->parent = p;


  if(!p)

    *T = node;

  else if(node->key < p->key)

    p->lchild = node;

  else

    p->rchild = node;


  node->color = RB_RED;

}


void rb_insert_color(rb_tree** T, rb_tree* node)

{

  rb_tree* parent;

  rb_tree* granpa;


  while((parent = node->parent) && RB_RED == parent->color)

  {

    granpa = parent->parent;


    if(granpa && granpa->lchild == parent)

    {

      rb_tree* uncle = granpa->rchild;


      if(uncle && RB_RED == uncle->color)

      {

        uncle->color = RB_BLACK;

        parent->color = RB_BLACK;

        granpa->color = RB_RED;

        node = granpa;

      }

      else if(parent->rchild == node)

      {

        node = parent;

        rb_rotate_left(T, node);

      }


      node->parent->color = RB_BLACK;

      granpa->color = RB_RED;

      rb_rotate_right(T, granpa);

    }

    else if(granpa && granpa->rchild == parent)

    {

      rb_tree* uncle = granpa->lchild;


      if(uncle && RB_RED == uncle->color)

      {

        uncle->color = RB_BLACK;

        parent->color = RB_BLACK;

        granpa->color = RB_RED;

        node = granpa;

      }

      else if(parent->lchild == node)

      {

        node = parent;

        rb_rotate_right(T, node);

      }


      node->parent->color = RB_BLACK;

      granpa->color = RB_RED;

      rb_rotate_left(T, granpa);

    }

  }


  (*T)->color = RB_BLACK;

}


void rb_insert(rb_tree** T, rb_tree* node)

{

  rb_insert_node(T, node);

  rb_insert_color(T, node);

}


3 删除

    删除的方法与二叉排序树一样,如果删除掉的是黑色,还需补一个黑色,然后进行分对称的四种情况来进行调节结点颜色,旋转次数不超过三次,这比AVL显然好很多。①node的兄弟sibing是红色;②node的兄弟sibing是黑色,且sibing的两个孩子是黑色;③node的兄弟是黑色,且sibing的两个孩子是红色;④node的兄弟是黑色,且sibing的左孩子是红色,右孩子是黑色;C++代码如下:

//Created by pritry

void rb_delete_color(rb_tree** T, rb_tree* node)

{

  rb_tree* parent;

  rb_tree* sibling;


  while(node != *T && RB_BLACK == node->color)

  {

    parent = node->parent;


    if(parent->lchild == node)

    {

      sibling = parent->rchild;


      if(RB_RED == sibling->color)

      {

        sibling->color = RB_BLACK;

        parent->color = RB_RED;

        rb_rotate_left(T, parent);

        sibling = parent->rchild;

      }


      if ((!sibling->lchild || RB_BLACK == sibling->lchild->color) && 

      (!sibling->rchild || RB_BLACK == sibling->rchild->color))

      {

        sibling->color = RB_RED;

        node = parent;

        parent = node->parent;

      }

      else

      {

        if(!sibling->rchild || RB_BLACK == sibling->rchild->color)

        {

          sibling->color = RB_RED;

          rb_rotate_right(T, sibling);

          sibling = parent->rchild;

        }


        sibling->color = parent->color;

        parent->color = RB_BLACK;

        sibling->rchild->color = RB_BLACK;

        rb_rotate_left(T, parent);


        node = *T;

      }

    }

    else

    {

      sibling = parent->lchild;


      if(RB_RED == sibling->color)

      {

        sibling->color = RB_BLACK;

        parent->color = RB_RED;

        rb_rotate_right(T, parent);

        sibling = parent->lchild;

      }


      if ((!sibling->lchild || RB_BLACK == sibling->lchild->color) && 

      (!sibling->rchild || RB_BLACK == sibling->rchild->color))

      {

        sibling->color = RB_RED;

        node = parent;

        parent = node->parent;

      }

      else

      {

        if(!sibling->lchild || RB_BLACK == sibling->lchild->color)

        {

          sibling->color = RB_RED;

          rb_rotate_left(T, sibling);

          sibling = parent->lchild;

        }


        sibling->color = parent->color;

        parent->color = RB_BLACK;

        sibling->lchild->color = RB_BLACK;

        rb_rotate_right(T, parent);


        node = *T;

      }


    }

  }


  node->color = RB_BLACK;

}


rb_tree* rb_delete_node(rb_tree** T, rb_tree* node)

{

  rb_tree* p;

  rb_tree* q;


  if(node->lchild && node->rchild)

  {

    rb_tree* left;

    p = node->rchild;

 

    while(left = p->lchild)

    p = left;

  }

  else

    p = node;


  if(p->lchild)

    q = p->lchild;

  else

    q = p->rchild;


  q->parent = p->parent;


  if(p->parent == NULL)

    *T = q;

  else if(p->parent->lchild == p)

    p->parent->lchild = q;

  else 

    p->parent->rchild = q;


  if(p != node) node->key = p->key;


  if(RB_BLACK == p->color)

    rb_delete_color(T, q);


  return p;

}


rb_tree* rb_delete(rb_tree** T, rb_tree* node)

{

  return rb_delete_node(T, node);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值