二叉查找树是最常用的一种二叉树,它支持快速插入、删除、查找操作,各个操作的时间复杂度跟树的高度成正比,理想情况下,时间复杂度是O(logn)。但是,二叉查找树在频繁的动态更新过程中,可能会出现树的高度远大于的情况,从而导致各个操作的复杂度降低。极端情况下,二叉树会退化为链表,时间复杂度会退化为O(n)。要解决时间复杂度退化问题,就需要设计一种平衡二叉查找树,而红黑树就是一种常见的平衡二叉查找树。
在工程中,很多用到平衡二叉查找树的地方都会用到红黑树。
1、什么是“平衡二叉查找树”?
平衡二叉树的定义是:二叉树中任意节点的左右子树的高度相差不能大于1。所以前面讲到的完全二叉树、满二叉树其实都是平衡二叉树,但是非完全二叉树也有可能是是平衡二叉树。
平衡二叉查找树不仅满足上面平衡二叉树的定义,还满足二叉查找树的特点。最先被发明的平衡二叉查找树是AVL树,它严格符合平衡二叉查找树的定义。但是也有很多平衡二叉查找树没有严格符合上面的定义(左右子树的高度相差不能大于1),比如要讲到的红黑树,它从根节点到各个叶子结点的最长路径,可能会比最短路径大一倍。
发明平衡二叉查找树这类数据结构的初衷,就是希望解决普通二叉查找树在频繁的插入、删除等动态更新的情况下,出现时间复杂度退化的问题。平衡二叉查找树中“平衡”的意思,其实就是让整棵树左右看起来比较“对称”、比较“平衡”,不要出现左子树很高、右子树很矮的情况,这样就可以让整棵树的高度相对来说低一点,从而相应的插入、删除、查找等操作的效率也高一些。
所以只要树的高度不比大很多,尽管不符合前面平衡二叉树的严格定义,但是仍然可以说这是一个合格的平衡的二叉树。
2、如何定义一棵“红黑树”?
红黑树的英文名是“Red-Black Tree”,简称R-B Tree,它是一种不严格定义的平衡二叉查找树。红黑树中的节点,一类被标记为黑色,一类被标记为红色。除此之外,一棵红黑树还需要满足下面这些要求:
- 根节点是黑色的;
- 每个叶子节点都是黑色的空节点(NIL),也就是说,叶子节点不存储数据;
- 任何相邻的节点都不能同时为红色,也就是说红色的节点是被黑色的节点隔开的;
- 每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点;
下面的画图跟讲解中,都将黑色的空叶子节点省略掉。
3、为什么说红黑树是“近似平衡”的?
如果要证明红黑树是近似平衡的,我们只需要分析,红黑树的高度是否稳定地趋近。
(1)如果我们将红色节点从红黑树中去掉,那单纯包含黑色节点的红黑树的高度是多少呢?
红色节点删除以后,有些节点就没有父节点,会直接拿这些节点的祖父节点作为父节点,所以之前的二叉树就会变成四叉树。所以包含黑色节点的四叉树,比包含相同节点个数的完全二叉树的高度还要小。完全二叉树的高度近似,所以去掉红色节点的“黑树”的高度不会超过
。
(2)知道只包含黑色节点的“黑树”的高度,那我们现在把红色节点加回去,高度会变成多少呢?
从红黑树的定义,红色节点不能相邻,也就是说有一个红色节点,至少有一个黑色节点,将它与其他红色节点隔开。红黑树中包含最多黑色节点的路径不会超过,所以加入红色节点以后,最长路径不会超过2
,也就是说,红黑树的高度近似2
。
所以,红黑树的高度,只是比高度平衡的AVL树的高度()仅仅大一倍,但是性能上下降的并不多。AVL树是一种高度平衡的二叉树,所以查找的效率非常高,但是,有利有弊,AVL树为了维护这种高度的平衡,每次插入、删除都要调整,就会比较复杂、耗时。所以对于有频繁的插入、删除操作的数据集合,使用AVL树的代价就比较高。红黑树只是做到近似平衡,并不是严格的平衡,所以在维护平衡的成本上,要比AVL树低。
红黑树的插入、删除、查找各种操作性能都比较稳定。对于工程应用来说,要面对各种异常情况,为了支撑这种工业级的应用,我们更倾向于这种性能稳定的平衡二叉查找树。