热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

算法导论笔记:1302红黑树插入

    红黑树的插入可在O(lgn)完成,红黑树的插入类似于二叉搜索树的插入,为了尽量维护红黑树的性质,将插入的新节点标记为RED,然后调用RB-INSERT-FIXUP对红黑树的

       红黑树的插入可在O(lg n)完成,红黑树的插入类似于二叉搜索树的插入,为了尽量维护红黑树的性质,将插入的新节点标记为RED,然后调用RB-INSERT-FIXUP对红黑树的性质进行维护,RB-INSERT代码如下:

 

RB-INSERT(T,z)        

       y = T.nil              

       x = T.root             

       while x != T.nil       

              y = x                  

              if z.key

                     x = x.left             

              else x = x.right       

       z.p = y   

            

       if y == T.nil          

             T.root= z            

      else  if  z.key

             y.left= z            

      else  y.right = z  

   

      z.left = T.nil        

      z.right = T.nil       

      z.color = RED     

   

       RB-INSERT-FIXUP(T, z) 

 

       RB-INSERT-FIXUP负责在插入之后,维护红黑树的性质,代码如下:

RB-INSERT-FIXUP(T,z)                

       while z.p.color == RED               

              if z.p == z.p.p. left                

                     y = z.p.p.right                      

                     if y.color == RED                    

                            z.p.color = BLACK                   // case 1          

                            y.color = BLACK                      // case 1            

                            z.p.p.color = RED                    // case 1          

                            z = z.p.p                                  // case 1  

                     else 

                            if z == z.p.right               

                                  z= z.p                                             //case 3                   

                                  LEFT-ROTATE(T,z)                      // case 3   

     

                           z.p.color= BLACK                             // case 2         

                           z.p.p.color= RED                              // case 2         

                           RIGHT-ROTATE(T,z.p.p)                 // case 2    

             else(same as then clause with “right” and “left” exchanged)

                     y = z.p.p.left                      

                     if y.color == RED                     

                            z.p.color = BLACK                    // case 1          

                            y.color = BLACK                       // case 1            

                            z.p.p.color = RED                    // case 1          

                            z = z.p.p                                  // case 1  

                     else 

                            if z == z.p.left               

                                  z = z.p                                          //case 3                   

                                  RIGHT-ROTATE(T,z)                 // case 3   

     

                           z.p.color= BLACK                          // case2         

                           z.p.p.color= RED                           // case2         

                           LEFT-ROTATE(T,z.p.p)                    // case 2 

 T.root.color = BLACK                

 

       对于新插入的结点z来说,因z的颜色为红色,所以,性质1,3,5都不会早到破坏,性质2,4有可能被破坏。如果z是根节点,则破坏了性质2,如果z的父节点为红色,则破坏了性质4。如果z的父节点z.p为黑色的话,则红黑树的性质没有发生改变。若z为根节点,则直接置rootcolorBLACK即可。所以只考虑z的父节点为RED的情况。

 

       根据z的父节点是左孩子或者右孩子的处理方法是对称的,所以只考虑z的父节点是左孩子的情况(if z.p == z.p.p. left)。根据z的叔叔结点y的颜色不同,以及z所处的位置,分为以下三种情况:

 

1:z的叔叔结点y的颜色为RED,记为case1:

       这种情况,不管z是左孩子,还是右孩子,都是同样的处理方法:

算法导论笔记:13-02红黑树插入z是右孩子

算法导论笔记:13-02红黑树插入z是左孩子。

       这种情况的处理代码是:

                            z.p.color = BLACK                   // case 1          

                            y.color = BLACK                       // case 1            

                            z.p.p.color = RED                    // case 1          

                            z = z.p.p                                  // case 1  

       得到下面的图:

算法导论笔记:13-02红黑树插入z是右孩子

算法导论笔记:13-02红黑树插入z是左孩子

 

     这种情况就是把z的父节点和叔叔结点y都变成BLACK,然后z的祖父结点变为RED,然后使祖父结点成为新的z,继续向上处理。

       这种处理方式,各个分支的黑高没有发生变化,同时维护了原红色z的父节点为BLACK的性质。

       这样处理之后,可以转变为剩下的情况2或者3的一种:

 

2:z的叔叔结点y的颜色为BLACK,z为左孩子,记为case2:

       这种情况下, 因为z的父节点是RED,所以z的祖父节点是BLACK,如下图:

算法导论笔记:13-02红黑树插入

       这种情况下的调整代码为:

                     z.p.color = BLACK                          // case 2         

                    z.p.p.color= RED                           // case 2         

                    RIGHT-ROTATE(T,z.p.p)  

       将z的父节点变为BLACK,祖父节点变为RED,同时对祖父节点进行右旋,得到下面的图:

算法导论笔记:13-02红黑树插入

       这种情况下,整个分支的黑高保持不变,同时内部分支的黑高也维持了性质5。同时,z的父节点不再是RED,所以退出循环。


3:z的叔叔结点y的颜色为BLACK,z为右孩子,记为case3:

       这种情况与case2类似,如下图;

算法导论笔记:13-02红黑树插入

       这种情况下的调整代码为:

                            z = z.p                                      // case 3                   

                           LEFT-ROTATE(T, z)                    // case 3 

调整后得到下面的图:

算法导论笔记:13-02红黑树插入

       调整后,各个分支的黑高没有发生任何变化,同时,变成了与case2吻合的情况。

 

分析:

       n个结点的红黑树高度为O(lg n),插入操作中,除了最后一步外,剩下的操作与二叉搜索树的插入相同,也就是时间复杂度为O(lg n)。在RD-INSERT-FIXUP中,仅当case1时,z才沿着树上升,while循环才会重复执行。所以while的重复次数为O(lgn)如果是case2或者3,则while循环直接结束。所以,RB-INSERT的时间复杂度为O(lg n)

 


推荐阅读
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 提升Python编程效率的十点建议
    本文介绍了提升Python编程效率的十点建议,包括不使用分号、选择合适的代码编辑器、遵循Python代码规范等。这些建议可以帮助开发者节省时间,提高编程效率。同时,还提供了相关参考链接供读者深入学习。 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • Monkey《大话移动——Android与iOS应用测试指南》的预购信息发布啦!
    Monkey《大话移动——Android与iOS应用测试指南》的预购信息已经发布,可以在京东和当当网进行预购。感谢几位大牛给出的书评,并呼吁大家的支持。明天京东的链接也将发布。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了游戏开发中的人工智能技术,包括定性行为和非定性行为的分类。定性行为是指特定且可预测的行为,而非定性行为则具有一定程度的不确定性。其中,追逐算法是定性行为的具体实例。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 006_Redis的List数据类型
    1.List类型是一个链表结构的集合,主要功能有push,pop,获取元素等。List类型是一个双端链表的结构,我们可以通过相关操作进行集合的头部或者尾部添加删除元素,List的设 ... [详细]
  • 本文介绍了一种解析GRE报文长度的方法,通过分析GRE报文头中的标志位来计算报文长度。具体实现步骤包括获取GRE报文头指针、提取标志位、计算报文长度等。该方法可以帮助用户准确地获取GRE报文的长度信息。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文主要复习了数据库的一些知识点,包括环境变量设置、表之间的引用关系等。同时介绍了一些常用的数据库命令及其使用方法,如创建数据库、查看已存在的数据库、切换数据库、创建表等操作。通过本文的学习,可以加深对数据库的理解和应用能力。 ... [详细]
author-avatar
情系初冬_883
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有