前言
二叉平衡树
1)空树
2)对于任何一个节点来说,它的左右两个子树的高度差的绝对值不超过1
红黑树
不算严格意义上的平衡树,它具有以下特点
1)节点有颜色,要么黑色要么红色
2)根节点必须是黑色
3)红色节点的左右两个子节点都是黑色
4)从任一节点到其每个叶子节点所有路径都包含相同数目的黑色节点个数
这些约束强制了红黑树的关键性质:从根节点到叶子节点的最长路径不大于最短路径的两倍长。这棵树是大致平衡的。
特点:可以在O(logn)的时间复杂度内做查找、插入和删除。
两颗树之间的对比
红黑树放弃了追求完全平衡,追求大致平衡,在与平衡二叉树的时间复杂度相差不大的情况下,保证每次插入最多只需要三次旋转(三次旋转的说法是否正确???)就能达到平衡,实现起来也更为简单。
平衡二叉树追求绝对平衡,条件比较苛刻,实现起来比较麻烦,每次插入新节点之后需要旋转的次数不能预知。执行插入还是删除操作,只要不满足上面的条件,就要通过旋转来保持平衡,而它的旋转非常耗时的。
可知平衡二叉树适合用于插入与删除次数比较少,但查找多的情况。实际工程中红黑树的运用比较多。比如HashMap底层的数据结构是数组+链表、数组+红黑树(JDK1.8之后)
平衡二叉树
由于平衡二叉树的第二个特性很容易被破坏,所以需要通过旋转的方式来保持平衡。
有以下四种情况:
情况分类 | 解决方案 |
LL型 | 右旋 |
RR型 | 左旋 |
LR型 | 先左旋后右旋 |
RL型 | 先右旋后左旋 |
前期知识储备
平衡因子=左子树的高度-右子树的高度
失衡节点的平衡因子的绝对值是大于1的。AVL树失衡类型的判断都基于这个失衡节点的。也就是说LL型需要调整的是失衡节点的左子树的左子树,LR型需要调整的是失衡节点左子树的右子树。
对於单旋转操作,就是以中间节点为中心旋转。而双旋转中,因为不是一次旋转,不能在一开始就确定旋转中心点,我们在第一次旋转的过程中,只是旋转后面的两个节点,并保证节点值的大小关系,
情况一:
LL型
情况二:
RR型
情况三:
RL型
情况四:
LR型
图片查考的地址:https://blog.csdn.net/HowardEmily/article/details/79543892 原作者若视为侵权,立即删除。
旋转的代码见此
(后序的补充)
红黑树
展开内容是 hashmapJDK1.8之前和之后的底层数据结构的分析,注:目前分析不牵扯源码,只是单纯数据结构分析。
HashMap1.8 底层数据结构是数组+链表和数组+红黑树
解决地址冲突问题,地址探测法和拉链法
1)当节点的个数大于8的时候,转成红黑树
2)当节点的个数小于6的时候,转成链表
为什么节点个数是8,6进行转换?
首先选择红黑树是为了提高查找效率,链表的查找时间复杂度是O(n),红黑树的查找时间复杂度是O(logn)
链表的平均查找的时间复杂度是O(n/2),在n=6的时候,时间复杂度为3
红黑树的平均查找的时间复杂度是O(logn),在n=8的时候,时间复杂度约等于3
结论:两个查找的时间复杂度几乎相等。所以设置了6和8这个临界值。中间过渡的节点是7,为了防止刚好在一个临界值进行频繁的删除和增加。