码迷,mamicode.com
首页 > 其他好文 > 详细

数据结构-红黑树

时间:2018-03-28 20:24:52      阅读:165      评论:0      收藏:0      [点我收藏+]

标签:har   const   修改   dep   class   new   highlight   兄弟节点   n+1   

红黑树的节点增加一个成员变量,表示节点的颜色:红色或是黑色.

通过对任何一条从根到分支尾部路径上各个节点颜色进行约束,红黑树确保没有一条路径会比其他路径长出两倍.近似的平衡

因此是近似平衡的.

1 红黑树特点

  1. 一定满足:每个节点或是红色或是黑色

  2. 一定满足:叶子节点(nullptr)是黑色

  3. 也就是子节点为nullptr,nullptr是黑色

    根节点是黑色

  4. 如果一个节点是红色,那么他的两个子节点都是黑色

    父子之间可以同时是黑色,但不能同时是红色

  5. 每个节点,从该节点到所有后代叶节点的简单路径上,均包含相同数目的黑色节点

因为,父子节点可以同为黑色,并且黑高相同,因此,差距最多为两倍:一条红黑相间,一条全为黑。

 

从任意节点出发,任意一条简单路径上的黑色节点个数成为黑高,bh.而红黑树的黑高为根节点的黑高.

n个节点的红黑树,黑高最大为2lg(n+1).

 

刚插入的节点染色为红色,因此需要调整

2 实现

2.1 节点结构

struct RBNode
{
  RBNode* left;
  RBNode* right;
  RBNode* p;
  char color; //取值为 r  b
  int key;
  string value;
  RBTree(const RBTree& node)
    :key(node.key),value(node.value),left(nullptr),right(nullptr),p(nullptr),
    color(‘r‘)//初始化的时候为黑色
    {}
};

 

2.2 插入insert

新插入的节点默认染为红色.

因此插入新节点以后,每个节点后依然会是红或黑,黑高不变(插入的染红了),

可能破坏的就是2和4:根节点是黑色(当之前为空的时候),

如果违反了性质2,表明,红黑树之前是一颗空的树,插入的节点变为根节点,此时根节点为红色.违反了.还有会面的迭代处理时候会违反。

违反性质4,表明,新插入节点的父节点也是红色.、

 

下面的代码还是找插入点的。

RBTree* RBTree::insert(const RBTree& node)
{
  RBTree* cur = mp_root;
  RBTree* pre = nullptr;
  while(cur != nullptr)
  {
    if(cur->key > node.key)
    {
      pre = cur;
      cur = cur->left;
    }else if(cur->key < node.key){
      pre = cur;
      cur = cur->left;
    }else if(cur->key == node.key)
    {
      return nullptr;
    }
  }
  
  RBTree* node = new RBTree(node);//color = ‘r‘
  
  if(pre == nullptr)
  {
    m_root = node;
  }else{
    if(pre->key>node.key)
    {
      pre->left =node;
    }else{
      pre->right = node;
    }
  }
  aux_insert_rebalance(node);
}

 

2.3 重新平衡

 

平衡的思路是这样的:

  1. 如果node节点没有父节点,那么表示,node是一个根节点,直接把node染黑就行了.

    满足了根节点是黑色.

  2. 如果node有父节点,其父节点颜色是黑色,那么满足一切条件

  3. 如果node父节点是红色.那么表明,node->p->p != nullptr,(node 的祖父节点需要是黑色)。同时也需要处理.

    根据如果node->p是左右节点来分别判断

    1. 如果node->p == node->p->p->left,同时存在node->p->p->right,而且node->p->p->right ==‘r‘

      意思是,父节点和叔节点都是红色,祖父节点是黑色,自己是红色

      此时,将祖父节点染红,然后叔父节点染黑.

      保持了黑高不变,但是讲违反规则的节点变为祖父节点

      因为,祖父节点的父节点可能是红色.

      node=node->p->p去处理祖父节点的违规.

      变为情况2,或3

    2. 如果node->p == node->p->p->right,同时存在node->p->p->right,而且node->p->p->right ==‘b‘

      当自己和父节点的都是红色,而自己是一个右节点的时候,叔节点是黑色,那么左旋自己,让自己变为左节点.

      变为情况3

    3. 如果node->p == node->p->p->left,同时存在node->p->p->right,而且node->p->p->right ==‘b‘

      当自己和父节点的都是红色,而自己是一个左节点的时候,叔节点是黑色

      直接右旋自己的祖父节点,,让自己和祖父节点处在同一级上,都是一红一黑.

      将父节点染黑,之前的祖父节点染红.

      处理完毕.

    4. 如果没有叔节点,那么默认叔节点是黑色的.

void RBTree::aux_insert_rebalance(RBTree *node)
{
  while(node->p !=nullptr && node->p->color == ‘r‘)
  {
    if(node->p=node->p->p->left)
    {
      uncle = node->p->p->right;
      if(uncle!=nullptr && uncle->color == ‘r‘)
      {
        //如果 node  的叔节点也是红色,那么表明node 的父节点也是红色.
        //因为黑高相等,叔叔是红色,因此祖父是黑色,因此父节点也是红色.
        //此时,修改叔节点和父节点为黑色,修改父节点为红色
        //因此保持红色节点不相连,黑高不变.
        //让 node 变为 node 的祖父,
        //去处理,祖父节点变为红色导致的性质破坏.
        node->p->color = ‘b‘;
        uncle->color =‘b‘;
        node->p->p->color = ‘r‘;
        node = node->p->p;
      }
      if(node==nodep->right && (uncle!=nullptr || uncle->color == ‘b‘))
      {
        //能到这里,表明 uncle 存在而且为黑色,或是uncle不存在
        //不存在的节点,默认为黑色.
        //并且 node 是一个右节点
        //旋转,让他变为左节点
        node=node->p;
        aux_rotate_l(node);
      }
      
      if(node==node->p->left && (uncle!=nullptr || uncle->color == ‘b‘))
      {
      	node->p->color = ‘b‘;
        node->p->p->color = ‘r‘;
        aux_rotate_r(node);
      }
    }else{
    //上面的 right 和 left 互换
    
    }
  }
  mp_root->color=‘b‘;
}

 

平衡操作的可行性:

整个平衡操作在于将不平衡状态变换到:自己和父节点是红色(一定是这种情况,而且祖父节点是黑色.),自己和父节点相对于祖父节点在同一方向,比如左左,然后,自己的叔节点是黑色(或空),而且,此时违反的规则一定是只有一个:红色不能相邻.

然后,旋转祖父节点,让自己的父节成为祖父节点,自己和祖父节点成为兄弟节点.此时,黑高变了,自己这一侧因为少了原先祖父节点(此时相对根节点是自己的父节点,是一个红色的.)而另一侧,没变(原先的祖父节点现在的父节点是自己的父节点,一个红色的),因此此时的变化,只需要讲自己的父节点染黑,然后,自己和原先的祖父节点染红.就不在违反黑高不变.

在平衡的过程中,利用的就是,路径上增加红色节点不会增加黑高,但是一直在打破红色不能相邻的规则,而,上面的规则恰好可以修复红色不相邻的规则.

数据结构-红黑树

标签:har   const   修改   dep   class   new   highlight   兄弟节点   n+1   

原文地址:https://www.cnblogs.com/perfy576/p/8665447.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!