红黑树怎么办?认真你就输了!

红黑树一直是各类无脑面试中的噩梦,就算不需要去编程,光是各种奇怪的扭转规则你都记不住。

那么何苦把它叫做红黑树呢?红黑树原来根本就不叫红黑树啊。

(参见Symmetric binary B-trees, Rudolf Bayer,1971)

红黑树相当于对称的2-3树。一句话就能表达清楚,每个[红,黑]总可以替换成一个2-3树节点。怎么个对称法?看下面的图:

图片来自百度百科
这棵树可以转换成这样子:(懒得画指针箭头)
在这里插入图片描述
这里我没把底层结点画成3-叶子,是想表示它下面可能还有一些别的结点没画出来(我才不承认是懒得画3-叶子),3-叶子结点是高度对称的。对于整棵树,我们可以不标记[黑->红]而标记[红->黑](下面这个画得比较拙,根结点不用拆两半的,可以画成[红<-黑->黑]的3-叶子的样子)
在这里插入图片描述
对2-3树来说两种情况都是合理的,相比之下,2-3树的搜索深度更小,但是红黑树比2-3树要节约不少内存资源,而且查找方便。

Rudolf那个论文里面描述红黑树是出奇的费劲,为嘛?因为他画图的时候是按2-3树的样子画的,还不加框框,用 ρ \rho ρ分支(黑->红) δ \delta δ分支(红->黑)描述这些指针,看了脑阔不疼才怪。相比之下红黑的叫法比这个简单易记不少。

很多人熟悉了红黑树再去看一个红黑树的时候就有直觉了,比如说他看到一个case能够不用刻意去想红黑树的规则,就能反应出下一步操作应该是什么扭转,仔细回想我们的“无意识”是怎么回事:

先找到最近的一个[黑,红]。
然后你看一下若不需要扭转,红红变黑红,黑红变红黑。
我们找到的[黑->红](或者[红<-黑])对应的是2-3树的结点。如果是[黑->红],黑一红二,[红->黑],黑二红一。如果父结点是黑,当然可以无脑插红。如果父结点是红呢?红结点这就插不进去了。然后做什么?
别想2-3树上溢,那个更烦人,对于这棵对称的2-3树,只要做一件事,那就是让它变成原来的对称形式,然后你就可以插入一个黑结点了!
这是什么操作?回想一下变色,不就是把原来的形式化成了对称的形式吗?
(以下的图叶子结点都没画成3-叶子结点,我才不承认我是懒得画三层就全不当叶子处理呢!)
在这里插入图片描述
这里没有扭转,单纯的变色,扭转其实只是Symmetric的时候使用了移动指针的对称操作,例如B1 <-- B2 --> B3 --> R4 --> R5这种情况,直接取对称(红黑变水平,黑红变竖直)之后仍然找不到合适的插入点(因为原来就是黑插红,但是找不到合适的红位置,直接取对称反而变成红插黑),此时只能通过改变局部对称结构的方式(也就是常见的扭转操作),颜色和数值不变,结构左右变成对称的,然后再插入。用 ρ \rho ρ-arc和 δ \delta δ-arc去解释可能会更容易接受。
在这里插入图片描述

扭转和变色操作其实是上述两棵2-3树之间的对称变换,每一次变色或者扭转都可以看作所有的Bnode从[红<-黑]到[黑->红]做了个对称变换,这也是为什么我们不用一个真正的2-3树去做,因为对称2-3树重构对称树不是一件容易的事情,但是给红黑树变个色就很简单,这也是作者设计巧妙之处,利用扭转配合变色操作实现对称2-3树之间的对称变换,就好像我们同时操作着两棵对称的B树,但是这两棵树又根本就不存在,实在是妙不可言。

红黑树比AVL树优越的地方在于它变色+扭转比AVL的纯扭转节约时间,红黑树的平均扭转次数比AVL树少得多,变色操作消耗的指令数更少。(有人说实际表现差别不大,我认为还是要看具体情况,而且,很多同学的测试都忽略了系统级别的一些干扰因素)

红黑树的缺点是,它并不是完美二叉树,而且为了考虑染色,要有大量额外的代码去维护,就算我们就算对红黑树的操作已经很熟悉了,要用代码去实现的时候还是很困难。编写代码和搞懂原理不是一回事,了解红黑树和2-3树的关系并不能帮助我们写红黑树的代码,编写代码必须有一种手感,对代码有足够的直觉。红黑树的代码写法就是分各类case,你把所有的特例都记住(或者抄在一张纸上的话),写起代码自然也轻松。就算是Bayer的原始论文里面,也就是一堆分类讨论而已,红黑树的发明人已经尽力将它们大大简化了。

虽然如此,红黑树的代码遍地都是(我才不承认我就是为了偷懒才不写一份源码贴上的嘞!),但是没有几份是真正值得读的(有一些人写的确实好,读过之后可能还是不会写红黑树,但是能学到很多东西),这大概就是人与机械的界限吧。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值