红黑树得定义:
其中,条件(1)和(2)意味着红节点均为内部节点,且其父节点及左、右孩子必然存在。另 外,条件(3)意味着红节点之父必为黑色,因此树中任一通路都不含相邻的红节点。
由此可知,在从根节点通往任一节点的沿途,黑节点都不少于红节点。除去根节点本身,沿途所经黑节点的总数称作该节点的黑深度(black depth),根节点的黑深度为0,其余依此 类推。故条件(4)亦可等效地理解和描述为“所有外部节点的黑深度统一”。 由条件(4)可进一步推知,在从任一节点通往其任一后代外部节点的沿途,黑节点的总数亦 必相等。除去(黑色)外部节点,沿途所经黑节点的总数称作该节点的黑高度(black height)。 如此,所有外部节点的黑高度均为0,其余依此类推。
需注意到如下有趣的事实:在红黑树 与8.2节的4阶B-树之间,存在极其密切的联系;经适当转换之后,二者相互等价! 具体地,自顶而下逐层考查红黑树各节点。每遇到一个红节点,都将对应的子树整体提升一 层,从而与其父节点(必黑)水平对齐,二者之间的联边则相应地调整为横向。
计算红黑树得高度:
可以看到红黑树等价于4阶B-树,从而由上面得转换可以看出,其4阶-B树的高度就是红黑树的叶节点的黑高度。很明显,红黑树的高度肯定是小于等于二倍黑高度的(这假设黑节点的父节点必是红节点的情况下);假设红黑树的高度为h,则,(假设此红黑树的节点数为n+1,4阶B-树的高度为H),从B-树的高度计算可知:
,因此红黑树的高度;
(知识点的总结来自邓俊辉的c++数据结构)
详细的插入情况讨论,就看邓公书里的介绍,我觉得挺详细得,我这里对其插入的时间复杂度做一点分析:
插入中双红的情况分为两种:第一种情况比较简单,只需要涉及到常数时间的重构,染色就可以恢复整棵红黑树的特性
而第二种情况调整后,却有可能发生上溢,从而还需向上不断调整,但是调整的时间复杂度不超过;
删除过程也是一样,大部分情况只需要调整一次即可,只有一种情况会发生上溢,但时间复杂度不超过树的高度
红黑树和AVL树的区别:
与AVL树不同的是,AVL树的插入和删除过程虽然也能保证在之内完成,但是在插入和删除过程种,红黑树的拓扑联接关系有所变化的节点绝不会超过常数个,但是AVL树却变化很大,这是二者之间最本质的一项差异;
且AVL树严格的保持着左右子树的高度差不超过1,而红黑树却不要这么严格,它通过标记节点的颜色,进行限制,来得到不大严格的平衡树,但是使插入和删除也保持在内,所以红黑树比较常用。但AVL树使严格的平衡树,从而其查找速度是比红黑树是快一点的。但是插入和删除就比较麻烦。所以,如果应用场景中对插入删除不频繁,只是对查找要求较高,那么AVL还是较优于红黑树。
红黑树和hash表的区别:
权衡三个因素: 查找速度, 数据量, 内存使用,可扩展性。
总体来说,hash查找速度会比红黑树快,而且查找速度基本和数据量大小无关,属于常数级别;而红黑树的查找速度是log(n)级别。当然不一定常数就比log(n) 小,
如果你考虑查找的效率,特别是在元素达到一定数量级时,hash表可以达到你的要求。
但是hash表的构造是比较占内存的,构造的刚开始,并不是每个节点都是有数据的,在STL中,hash表刚开始的容量比你指定的大,并且当超过里面容量的时候,需要更大的内存,那么复制之前的数据也是一笔不小的消耗,而红黑树中每个节点都是存在的,内存消耗比较小,如果对内存有要求,则可以使用红黑树
如果数据是静态的,只涉及到频繁的查找过程,那么hash函数是比较好的选择,因为其只需要常数的时间。但是红黑树却需要
使用红黑树而不是散列表被实践证明具有更好的伸缩性。Linux内核在管理vm_area_struct时就是采用了红黑树来维护内存块的。epoll中关于文件描述符的节点就是用红黑树来动态管理的。
并且红黑树的数据是有序的,而hash表并不是。