第十三章 红黑树
首先说一下本章有一个地方的图有误,P168页的图,正确的图如下(case3有误,中文版):
在Linux内核和STL中,都大量使用了红黑树这种数据结构,原因是红黑树的搜索、插入和删除效率都很高。
红黑树是一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是RED(红色)或BLACK(黑色)。
一棵红黑树有如下性质:
(1)每个结点要么是红的,要么是黑的。
(2)根结点是黑的。
(3)每个叶结点,即空结点(NIL)是黑的。
(4)如果一个结点是红的,那么它的俩个儿子都是黑的。
(5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。
树中每个结点有五个域:color,key,left,right和p。一棵有n个内结点的红黑树的高度至多为2lg(n+1)。
红黑树的操作:
1、旋转
当在红黑树上进行插入或删除操作时,树的红黑性质将被破坏。为了保持这些性质,就要改变树中某些结点的颜色及指针的结构。其中指针结构的修改是通过旋转来完成的。旋转是一种能保持持树中结点的中缀次序的局部操作。下图是两种旋转方法,左旋和右旋。
2、插入
情况1:如下图所示,X为新插入的结点,将其涂为红色。P为X的父结点,也为红色。G是X的祖父结点,S是X的叔父结点,它们都为黑色。这时X、P和G成一直线排列,此种情况的处理方式比较简单,只要采用一个单旋转操作,并进行适当的颜色调整即可。首先进行一个右单旋转,然后修改G的颜色。
情况2:如下图所示,X为新插入的结点,将其涂为红色。P为X的父结点,也为红色。G是X的祖父结点,S是X的叔父结点,它们都为黑色。这是X、P和G成一折线排列,此种情况的处理方式是采用一个双旋转操作,并进行适当的颜色调整即可。首先进行一个先左后右的双旋转,旋转过程中修改X和G的颜色。
情况3:情况1和情况2都相对简单,但是如果新插入结点X的叔父结点S为红色,有可能无论如何旋转总是会出现“红-红结点”的情况。这时采用逐层上升的调整和着色。
如下图所示的情况,仍然比较简单,一个右单旋转就解决了问题。
下图所示的情况则复杂一些。图a为插入结点16的过程。因为16及其父结点17都是红的,帮违反了性质3。又因为16的叔父结点22也是红的,则属于情况3。各结点被重新着色,指针沿树上升,所得的树如下图b所示。如此,结点21及其父亲结点又都为红色,但结点21的叔父结点30是黑的。由于21是15的右孩子,故可应用情况2进行处理,在执行一次左旋转后,所得结果树如图c。执行一次右旋后得图d中的树。它是一棵合法的红黑树,插入操作完成。