前两篇文章谈了B-Tree和B+Tree,它们属于多路平衡树,所有叶子结点都在同一层,除了这两种平衡树, 我们熟知的还有平衡二叉树和红黑树。这一篇文章就来看看如何构建红黑树
对于平衡二叉树的构建,可以参考小程序中的文章(C++版)。
平衡二叉树
红黑树属于平衡二叉树,但是并非严格意义上的平衡二叉树,因为平衡二叉树要求节点的左右子树高度差不超过1, 而红黑树放弃了这种高度平衡,利用对结点上色的操作来保证树相对平衡,这其中原因大概是维护一个绝对平衡的二叉树代价太大, 在插入操作比较频繁的情况下,其性能上的收益并不大(HashMap采用红黑树而不是平衡二叉树的原因)。
但如果插入频率小或者只有一次构建,那么平衡二叉树的查询性能还是比红黑树高。
1> 所有结点颜色是黑色或者红色
2> 根结点为黑色
3> 每个叶子结点为黑色(这里的叶子结点指的是为null的结点)
4> 红色结点的孩子结点必须是黑色结点
5> 任意一结点到每个叶子结点所经过的黑结点个数相同
从上面的性质我们大概知道红黑树的结构,树根为黑色,不存在连续的两个红色结点,每个子树分支的黑结点个数相同,如下图
同平衡二叉树一样,构建过程中,平衡逻辑是最关键的,通常情况下,我们插入的结点默认是红色,因为这样不会打破性质五,使得任一结点到每个叶子结点所经过的黑结点个数相同。
此时红黑树构建平衡分为4种情况:
情况一:红黑树为空树,此时插入结点充当根结点,上色为黑
情况二:插入结点已经存在,此时替换插入结点值即可
情况三:插入结点的位置,其父结点是黑色,此时平衡未打破,插入完成
情况四:插入结点的父结点是红色,此时平衡打破,需要进行平衡操作。
当情况四出现时候,说明需要进行平衡操作,此时操作逻辑如下:
图一的平衡过程是将-1设置为黑色,1设置为红色,以1结点为基准进行右旋
图二的平衡过程是将2设置为黑色,1设置为红色,然后以1结点为基本进行左旋。
注:也可以将-2/5设置为黑色,然后以1右旋/左旋,但是此时-1/2为红色,如果父结点为红色, 那么需要继续平衡
平衡结果:
平衡
我们依次插入1,-1,-2,-3,2,5,4,3来看一下红黑树的构建的过程
插入1,构建根结点:情况一
插入-1,构建孩子结点:情况三
插入-2,失衡,情况4.1
插入-3,失衡,情况4.3
插入2,情况三,未失衡
插入5,失衡,情况4.1
插入4,失衡,情况4.3
插入3,失衡,情况4.1
到这里就构建完成了
相对于构建新增,红黑树的删除情况更为复杂,由于时间关系(这周只有一天休息加上绘图太费劲),留到下一次分享。
红黑树构建源码