动力节点首页 全国咨询热线:400-8080-105

绑定手机号,登录
手机号

验证码

微信登录
手机号登录
手机号

验证码

30天自动登录
微信登录与注册
微信扫码登录与注册

扫码关注微信公众号完成登录与注册
手机号登录
首页 > 文章

红黑树的原理

04-11 20:29 334浏览
举报 T字号
  • 大字
  • 中字
  • 小字

我们都听过平衡二叉树(AVLTree),了解到AVL树的性质,其实平衡二叉树最大的作用就是查找,AVL树的查找、插入和删除在平均和最坏情况下都是O(logn)。AVL树的效率就是高在这个地方。如果在AVL树中插入或删除节点后,使得高度之差大于1。此时,AVL树的平衡状态就被破坏,它就不再是一棵二叉树;为了让它重新维持在一个平衡状态,就需要对其进行旋转处理, 那么创建一颗平衡二叉树的成本其实不小. 这个时候就有人开始思考,并且提出了红黑树的理论,那么红黑树到底比AVL树好在哪里?

红黑树与AVL树的比较:

  • AVL树的时间复杂度虽然优于红黑树,但是对于现在的计算机,cpu太快,可以忽略性能差异
  • 红黑树的插入删除比AVL树更便于控制操作
  • 红黑树整体性能略优于AVL树(红黑树旋转情况少于AVL树)

1.红黑树的性质

红黑树是一棵二叉搜索树,它在每个节点增加了一个存储位记录节点的颜色,可以是RED,也可以是BLACK;通过任意一条从根到叶子简单路径上颜色的约束,红黑树保证最长路径不超过最短路径的二倍,因而近似平衡。

具体性质如下:

  • 每个节点颜色不是黑色,就是红色
  • 根节点是黑色的
  • 如果一个节点是红色,那么它的两个子节点就是黑色的(没有连续的红节点)
  • 对于每个节点,从该节点到其后代叶节点的简单路径上,均包含相同数目的黑色节点

你的最短路径就是全黑节点,最长路径就是一个红节点一个黑节点,最后黑色节点相同时,最长路径刚好是最短路径的两倍

2.红黑树的插入

红黑树插入节点过程大致分析:

RBTree为二叉搜索树,我们按照二叉搜索树的方法对其进行节点插入

RBTree有颜色约束性质,因此我们在插入新节点之后要进行颜色调整

具体步骤如下:

  • 根节点为NULL,直接插入新节点并将其颜色置为黑色
  • 根节点不为NULL,找到要插入新节点的位置
  • 插入新节点
  • 判断新插入节点对全树颜色的影响,更新调整颜色

首先红黑树的插入其实不是那么容易实现的,以前搜索树的插入我们很容易理解现在我们首先思考一个问题,你插入节点的默认颜色是RED或BLACK? 这里我们需要根据性质来思考,首先如果插入黑节点,这个可以直接插入无论它的父亲是什么颜色,但是红黑树的性质是每条路径的黑色节点数目相同这个时候你再想想那其他路径的黑色节点数目一定比你现在少一个节点,所以调整起来是非常繁琐的. 插入红节点不需要调整其他路径,如果它的父亲为黑,那么直接插入,如果他的父亲为红那么在该路径上面开始分情况调整. 所以插入节点默认颜色一定要为红.如果为黑调节成本太大了.接下来开始插入节点如果插入节点的父亲为黑那么直接插入后返回不需要做任何调整. 但是如果插入节点的父亲为红,那么就需要调整了.具体的调整过程可以分为三个情况:

第一种情况

cur为红,parent为红,pParent为黑,uncle存在且为红

则将parent,uncle改为黑,pParent改为红,然后把pParent当成cur,继续向上调整。

此时对该子树进行操作,parent节点和uncle节点变为黑,pParent节点变为红,这样我们就保证该子树中每条路径中黑色节点相同并且没有连续的红节点,然后再让cur等于pParent节点继续往上继续调整。

第二种情况

cur为红,parent为红,pParent为黑,uncle不存在/u为黑

parent为pParent的左孩子,cur为parent的左孩子,则进行右单旋转;

第三种情况

cur为红,p为红,g为黑,u不存在/u为黑

p为g的左孩子,cur为p的右孩子,则针对p做左单旋转

则转换成了情况2

boolean Insert( const K& key, const V& value)
     {
         //根节点为空
         if (_root == NULL)
         {
             _root = new Node(key,value);
             _root->_color = BLACK;
 
             return true ;
         }
         //根节点不为空
 
         //找到新节点插入位置
         Node* parent = NULL;
         Node* cur = _root;
 
         while (cur)
         {
             if (cur->_key < key)
             {
                 parent = cur;
                 cur = cur->_right;
             }
             else if (cur->_key >key)
             {
                 parent = cur;
                 cur = cur->_left;
             }
             else
                 return false ;
         }
         //插入新节点
         cur = new Node(key, value);
         cur->_color = RED;
         if (parent->_key > key)
         {
             parent->_left = cur;
             cur->_parent = parent;
         }
         else //parent->_key < key
         {
             parent->_right = cur;
             cur->_parent = parent;
         }
 
         //插入节点后颜色的调整
         while (parent && parent->_color == RED)
         {
             Node* grandfather = parent->_parent; //grandfather颜色一定为黑色
             if (parent == grandfather->_left)
             {
                 Node* uncle = grandfather->_right;
 
                 //uncle存在且为红
                 if (uncle && uncle->_color == RED)
                 {
                     parent->_color = uncle->_color = BLACK;
                     grandfather->_color = RED;
 
                     cur = grandfather;
                     parent = cur->_parent;
                 }
                 else //uncle不存在/uncle存在且为黑
                 {
                     if (cur == parent->_right)
                     {
                         RotateL(parent);
                         swap(parent, cur);
                     }
                     RotateR(grandfather);
                     parent->_color = BLACK;
                     grandfather->_color = RED;
                 }
             }
             else //grandfather->_right==parent
             {
                 Node* uncle = grandfather->_left;
 
                 //uncle存在且为红
                 if (uncle && uncle->_color == RED)
                 {
                     parent->_color = uncle->_color = BLACK;
                     grandfather->_color = RED;
 
                     cur = grandfather;
                     parent = cur->_parent;
                 }
                 else //不存在/存在且为黑
                 {
                     if (cur == parent->_left)
                     {
                         RotateR(parent);
                         swap(cur, parent);
                     }
 
                     RotateL(grandfather);
                     parent->_color = BLACK;
                     grandfather->_color = RED;
                 }
             }
         } //end while (parent && parent->_color == RED)
 
         _root->_color = BLACK;
 
         return true ;
}
0人推荐
共同学习,写下你的评论
0条评论
代码小兵669
程序员代码小兵669

6篇文章贡献30667字

相关课程 更多>

作者相关文章更多>

推荐相关文章更多>

Java初学者学习方法

代码小兵64503-29 11:46

两道经典算法问题

代码小兵51603-29 13:18

Java中模拟高并发的方法

代码小兵87208-06 11:36

Java程序员必备的一些流程图

代码小兵64503-29 15:27

Java接口限流的实现方法

代码小兵57603-29 17:52

发评论

举报

0/150

取消