前言
前几天学习了ConcurrentHashMap的一些结构,了解了底层通过链表以及红黑树来实现的数据结构,所以在此基础上想要学习红黑树的一些知识。当然了既然要学习红黑树就要从二叉树、平衡二叉树进行学习,毕竟红黑树是在平衡二叉树的基础上进行变形。既然学习了红黑树那么也要同时学习B-Tree(B
杠
Tree,不是B减
Tree)以及B+Tree。今天就把自己学习到的一些关于树的知识进行整理总结。
1、二叉树
1.1定义:
在计算机科学中,二叉树是每个结点最多有两个子树的树结构。--------来自百度百科
与根结点相连的两个子树成为左子树、右子树。
1.2结构:
图片摘自:https://blog.csdn.net/u014209205/article/details/81043002
1.3特点/性质:
二叉树中有如下特点:
- 每个结点最多有两棵子树,所以二叉树中不存在度大于2的结点。
- 二叉树的子树有左右之分,次序不能任意颠倒。
- 左子树的键值小于根的键值,右子树的键值大于根的键值。
1.4总结:
- 二叉树的时间复杂度为O(Log2n),近似与折半查找,但是二叉树完全不平衡时,二叉树成为了链表,时间复杂度变为O(n)。因此二叉排序树的查找性能在O(Log2n)到O(n)之间。
- 通过以上的二叉树结构中我们可以看到存在结点都在一个子树的问题,这样就导致了二叉树的深度增加,从而影响了二叉树的效率,为了解决这种效率就提出了
平衡二叉树(AVL树)
。
2、平衡二叉树(AVL树)
2.1定义:
平衡二叉树是一种特殊的二叉树,是为了解决二叉树中所有结点都在一个子树的问题。平衡二叉树通过一种平衡算法使所有落在树上的结点保持树的平衡性(左子树和右子树的深度(高度)之差的绝对值不超过1;左子树和右子树都是平衡二叉树)
。
2.2结构:
图片摘自:https://blog.csdn.net/qq_25940921/article/details/82183093
2.3特点/性质:
平衡二叉树(AVL树)的特点:
- 满意二叉树的条件
- 左子树和右子树都是平衡二叉树
- 左子树和右子树的深度(高度)之差的绝对值不超过1
- 新增和删除操作可能造成平衡二叉树失去平衡
2.4变换:
在平衡二叉树中新增和删除操作都有可能导致平衡二叉树失去平衡,为了维持平衡二叉树的平衡性,需要通过一定的旋转操作来使平衡二叉树重新达到平衡。
2.4.1:左旋(LL旋转)
在以上的平衡二叉树的结构中,结点1
的存在导致了根结点5
的失衡,为了保持平衡,需要对根结点5
进行LL旋转,LL旋转过程:
1. 结点5的左结点结点3代替结点5,
2. 结点5成为了结点3的右结点,
3. 结点4调整位置成为结点5的左结点。
最后调整结构如下:
2.4.2右旋(RR旋转)
上图的平衡二叉树的结构中,根结点6的存在导致了根结点2的失衡,为了维持平衡需要对结点2进行右旋(RR旋转),RR旋转的过程:
1. 结点2的右节点结点4代替结点2
2. 结点2成为结点4的左结点
3. 结点3调整位置成为结点2的右节点
最后旋转效果如下:
2.4.3左右旋(LR旋转)
在以上的结构中,结点3导致了结点5的失衡,结点3位于结点5的左子树的右子树上,所以我们在进行旋转操作时,需要两次旋转才能调节平衡,因为我们直接对结点5进行LL旋转
时,结点2的右子树
无法进行调整,所以我们需要先调整结点2
的右子树(RR旋转
),然后再调整结点5(LL旋转)
。调整过程如下(先上图,通过看图分析):
1. 结点2进行RR旋转:结点4代替结点2,结点2成为结点4的左结点,结点3调整位置成为结点2的右节点
2. 然后对结点5进行LL旋转:结点4代替结点5,结点5成为结点4的右节点
2.4.4右左旋(RL旋转)
以上图中,结点3的存在导致了结点2失衡,结点3位于结点2的右子树的左子树,需要两次旋转来调节平衡,第一次旋转使问题结点成为结点6,这样就可以使用LL旋转进行调整。
第一次对结点5进行LL旋转,然后再对结点2进行RR旋转。调整过程如下:
- 结点5进行LL旋转:结点4代替结点5,结点5成为结点4的右节点
- 结点2进行RR旋转:结点4代替结点2,结点2成为结点4的左结点,结点3调整位置成为结点2的右节点
2.5总结
- 平衡二叉树中通过一系列的旋转来维持平衡
- 插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN),但是频繁的旋转会消耗一定的时间。
3、红黑树
3.1定义:
因为平衡二叉树会维持绝对的平衡,所以在进行插入、删除时会频繁的进行旋转
,从而造成性能的问题,为了解决该问题,提出了红黑树
。
红黑树是一种特化的AVL树(平衡二叉树),都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。------来读百度百科
红黑树是一个自平衡(不是绝对的平衡)的二叉查找树。
3.2结构:
图片来自:https://www.cnblogs.com/fornever/archive/2011/12/02/2270692.html
3.3特点/性质:
- 结点是红色或黑色。
- 根结点是黑色。
- 每个叶子节点(NIL)是黑色。
- 如果一个节点是红色的,则它的子节点必须是黑色的。
- 任意一结点到每个叶子结点的路径都包含数量相同的黑结点(
也就是如果一个结点存在黑结点,那么该结点肯定有两个子结点
)。
3.4分析:
通过红黑树的特点以及性质,限定了红黑树不会退化成为链表,同时也保证了任意节点到其每个叶子节点路径最长不会超过最短路径的2倍。可以通过下图来理解:
上图中最短路径都是由黑色结点组成,最长路径有四条
(图中只画出两条),并且每条最长路径都包含相同数量的黑色结点,并且最长路径的长度最短路径的两倍
。
最长路径为:
M---->Q---->Y---->Z
M---->Q---->Y---->X
M---->Q---->O---->N
M---->Q---->O---->P
最短路径为:
M---->E
图片来自:https://www.jianshu.com/p/e136ec79235c
红黑树并不是绝对平衡的二叉树,所以并不会像平衡二叉树那样要求左子树与右子树的高度差为1,红黑树通过任意一结点到每个叶子结点的路径都包含数量相同的黑结点
这个性质来达到自己的平衡。
3.5变换:
红黑树的旋转以及变换颜色的过程自己暂时还没想通怎么处理,因为红黑树不仅涉及到旋转,还需要在插入时进行颜色的变换。这里自己没想通,所以这里就不做描述了,有兴趣的可以看下这几个博主。
https://segmentfault.com/a/1190000012728513
https://www.cnblogs.com/skywang12345/p/3245399.html
3.6总结:
- 通过红黑树很好的解决了平衡二叉树存在的频繁旋转的问题,提高了一定的性能。
- 红黑树和平衡二叉树在检索的时候效率差不多,都是通过平衡进行二分查找,时间复杂度都是O(lnN)
- 在删除和修改时,红黑树的效率更好,这是因为红黑树不像AVL树更为严格的平衡,允许局部的很少的不完全平衡,但是影响不大,从而省去了很多没必要的调节平衡的操作,AVL需要更多的旋转次数来调节平衡的数据结构,所以效率不如红黑树。这样在HashMap以及ConcurrentHashMap中,在插入、更新、删除数据时不需要频繁的旋转,提高了这些操作的性能,所以HashMap以及ConcurrentHashMap采用红黑树而不是平衡二叉树。
结语:
以上就是自己对于二叉树、平衡二叉树、红黑树的整理以及总结,也加深自己对这三个树的认识,下面再整理B-Tree以及B+Tree的知识。